带绑定的触发样式更新,相关来源
问题描述:
我正在修改RadioButton以用作iOS中已知的分段控件。带绑定的触发样式更新,相关来源
我的改装风格看起来是这样的:
<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他TintColor
和SelectedTextColor
更新?正如你可以从两个在线评论中看到的,我通过翻转IsChecked
值来更新/重新绘制
答
我结束了使用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>
我觉得没有任何问题。您将“IsChecked”属性设置为false,并重置为true,以触发控件模板中的“已检查”可视状态。然后,您的控件可以及时更新颜色。 – Skyblue
是的,这有效,但我觉得它有点哈克。我结束了你使用视觉状态管理器。它仍然感觉有点冒险,但现在我的想法更加清晰。 –