2017-10-15 110 views
0

我正在修改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

是的,這有效,但我覺得它有點哈​​克。我結束了你使用視覺狀態管理器。它仍然感覺有點冒險,但現在我的想法更加清晰。 –

回答

1

我結束了使用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>