带绑定的触发样式更新,相关来源

带绑定的触发样式更新,相关来源

问题描述:

我正在修改RadioButton以用作iOS中已知的分段控件。带绑定的触发样式更新,相关来源

下面是它的外观: enter image description here

我的改装风格看起来是这样的:

<Style TargetType="control:SegmentRadioButton" x:Key="SegmentedRadioButtonStyle"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="control:SegmentRadioButton"> 
       <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"> 
        <ContentPresenter 
         x:Name="ContentPresenter" 
         Padding="{TemplateBinding Padding}" 
         HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
         VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" 
         AutomationProperties.AccessibilityView="Raw" 
         BorderThickness="{TemplateBinding BorderThickness}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         Content="{TemplateBinding Content}" 
         ContentTemplate="{TemplateBinding ContentTemplate}" 
         ContentTransitions="{TemplateBinding ContentTransitions}" 
         Background="{TemplateBinding Background}" 
         Foreground="{TemplateBinding Foreground}"/> 
        <VisualStateManager.VisualStateGroups> 
         <VisualStateGroup x:Name="CommonStates"> 
          <VisualState x:Name="Normal"> 
           <Storyboard> 
            <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" /> 
           </Storyboard> 
          </VisualState> 
         </VisualStateGroup> 
         <VisualStateGroup x:Name="CheckStates"> 
          <VisualState x:Name="Checked"> 
           <Storyboard> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding SelectedTextColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding TintColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="Unchecked"> 
           <Storyboard> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="Indeterminate" /> 
         </VisualStateGroup> 
        </VisualStateManager.VisualStateGroups> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

而我得到的控制是这样的:

public class SegmentRadioButton : RadioButton 
{ 
    public static readonly DependencyProperty SelectedTextColorProperty = DependencyProperty.Register(
     "SelectedTextColor", 
     typeof(SolidColorBrush), typeof(SegmentRadioButton), 
     new PropertyMetadata(default(SolidColorBrush), new PropertyChangedCallback(OnSelectedTextChanged))); 

    public SolidColorBrush SelectedTextColor 
    { 
     get => (SolidColorBrush) GetValue(SelectedTextColorProperty); 
     set => SetValue(SelectedTextColorProperty, value); 
    } 

    public static readonly DependencyProperty TintColorProperty = DependencyProperty.Register(
     "TintColor", typeof(SolidColorBrush), typeof(SegmentRadioButton), new PropertyMetadata(default(SolidColorBrush), new PropertyChangedCallback(OnTintChanged))); 

    public SolidColorBrush TintColor 
    { 
     get => (SolidColorBrush) GetValue(TintColorProperty); 
     set => SetValue(TintColorProperty, value); 
    } 

    public SegmentRadioButton() 
    { 

    } 

    private static void OnTintChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (d is SegmentRadioButton segment) 
     { 
      segment.BorderBrush = (SolidColorBrush) e.NewValue; 

      if (segment.IsChecked ?? false) 
      { 
       // Hack to make the selected segment re-draw. 
       segment.IsChecked = false; 
       segment.IsChecked = true; 
      } 
     } 
    } 

    private static void OnSelectedTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (d is SegmentRadioButton segment) 
     { 
      if (segment.IsChecked ?? false) 
      { 
       // Hack to make the selected segment re-draw. 
       segment.IsChecked = false; 
       segment.IsChecked = true; 
      } 
     } 
    } 

} 

的问题:这实际工作,但我想知道是否有更优雅和更少的方法来使t他TintColorSelectedTextColor更新?正如你可以从两个在线评论中看到的,我通过翻转IsChecked值来更新/重新绘制

+0

我觉得没有任何问题。您将“IsChecked”属性设置为false,并重置为true,以触发控件模板中的“已检查”可视状态。然后,您的控件可以及时更新颜色。 – Skyblue

+0

是的,这有效,但我觉得它有点哈​​克。我结束了你使用视觉状态管理器。它仍然感觉有点冒险,但现在我的想法更加清晰。 –

我结束了使用Visual状态管理器和一个简单的刷新。

的代码是在GitHub上:Plugin.SegmentedControl

这里是代码的关键部分,因为它现在看起来:

public class SegmentRadioButton : RadioButton 
{ 
    public static readonly DependencyProperty SelectedTextColorProperty = DependencyProperty.Register(
     "SelectedTextColor", 
     typeof(SolidColorBrush), typeof(SegmentRadioButton), 
     new PropertyMetadata(default(SolidColorBrush), new PropertyChangedCallback(OnSelectedTextChanged))); 

    public SolidColorBrush SelectedTextColor 
    { 
     get => (SolidColorBrush) GetValue(SelectedTextColorProperty); 
     set => SetValue(SelectedTextColorProperty, value); 
    } 

    public static readonly DependencyProperty TintColorProperty = DependencyProperty.Register(
     "TintColor", typeof(SolidColorBrush), typeof(SegmentRadioButton), new PropertyMetadata(default(SolidColorBrush), new PropertyChangedCallback(OnTintChanged))); 

    public SolidColorBrush TintColor 
    { 
     get => (SolidColorBrush) GetValue(TintColorProperty); 
     set => SetValue(TintColorProperty, value); 
    } 

    public static readonly DependencyProperty DisabledColorProperty = DependencyProperty.Register(
     "DisabledColor", typeof(SolidColorBrush), typeof(SegmentRadioButton), new PropertyMetadata(default(SolidColorBrush), new PropertyChangedCallback(OnDisabledColorChanged))); 

    public SolidColorBrush DisabledColor 
    { 
     get => (SolidColorBrush) GetValue(DisabledColorProperty); 
     set => SetValue(DisabledColorProperty, value); 
    } 


    public SegmentRadioButton() 
    { 
     this.IsEnabledChanged += SegmentRadioButton_IsEnabledChanged; 
    } 

    private void SegmentRadioButton_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     if (sender is SegmentRadioButton segment) 
     { 
      Refresh(segment); 
     } 
    } 

    private static void OnTintChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (d is SegmentRadioButton segment) 
     { 
      segment.BorderBrush = (SolidColorBrush) e.NewValue; 
      Refresh(segment); 
     } 
    } 


    private static void OnDisabledColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (d is SegmentRadioButton segment) 
     { 
      segment.BorderBrush = (SolidColorBrush)e.NewValue; 
      Refresh(segment); 
     } 
    } 

    private static void OnSelectedTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (d is SegmentRadioButton segment) 
     { 
      Refresh(segment); 
     } 
    } 

    private static void Refresh(SegmentRadioButton segment) 
    { 
     // Go to "Indeterminate" State to ensure that the GotoState is refreshed even if the state is the same. 
     // Necessary because properties might have changed even when the state have not. 

     VisualStateManager.GoToState(segment, "Indeterminate", false); 

     if (segment.IsChecked ?? false) 
     { 
      VisualStateManager.GoToState(segment, segment.IsEnabled ? "Checked" : "DisabledAndChecked", false); 
     } 
     else 
     { 
      VisualStateManager.GoToState(segment, segment.IsEnabled ? "Unchecked" : "DisabledAndUnchecked", false); 
     } 
    } 
} 

风格:

<Style TargetType="control1:SegmentRadioButton" x:Key="SegmentedRadioButtonStyle"> 
    <Setter Property="UseSystemFocusVisuals" Value="True" /> 
    <Setter Property="VerticalContentAlignment" Value="Center"></Setter> 
    <Setter Property="HorizontalContentAlignment" Value="Center"/> 
    <Setter Property="Padding" Value="8,4,8,4"></Setter> 
    <Setter Property="Background" Value="Transparent"></Setter> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="control1:SegmentRadioButton"> 
       <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"> 
        <ContentPresenter 
         x:Name="ContentPresenter" 
         Padding="{TemplateBinding Padding}" 
         HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
         VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" 
         AutomationProperties.AccessibilityView="Raw" 
         BorderThickness="{TemplateBinding BorderThickness}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         Content="{TemplateBinding Content}" 
         ContentTemplate="{TemplateBinding ContentTemplate}" 
         ContentTransitions="{TemplateBinding ContentTransitions}" 
         Background="{TemplateBinding Background}" 
         Foreground="{TemplateBinding Foreground}"/> 
        <VisualStateManager.VisualStateGroups> 
         <VisualStateGroup x:Name="CommonStates"> 
          <VisualState x:Name="Normal"> 
           <Storyboard> 
            <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" /> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="DisabledAndChecked"> 
           <Storyboard> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding DisabledColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding SelectedTextColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding DisabledColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="DisabledAndUnchecked"> 
           <Storyboard> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding DisabledColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding DisabledColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
           </Storyboard> 
          </VisualState> 
         </VisualStateGroup> 
         <VisualStateGroup x:Name="CheckStates"> 
          <VisualState x:Name="Checked"> 
           <Storyboard> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding TintColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding SelectedTextColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding TintColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="Unchecked"> 
           <Storyboard> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding TintColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding TintColor, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" /> 
            </ObjectAnimationUsingKeyFrames> 
           </Storyboard> 
          </VisualState> 

          <VisualState x:Name="Indeterminate" /> 
         </VisualStateGroup> 
        </VisualStateManager.VisualStateGroups> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style>