我正在创建一个自定义控件,我想添加一个与CheckBox.IsChecked类似的依赖项属性,即当用户单击控件时,绑定将更新源。此自定义控件的声明如下:
public class QuadStateSelector : Control
{
static QuadStateSelector()
{
PropertyChangedCallback callback = new PropertyChangedCallback(OnValueChanged);
FrameworkPropertyMetadata md = new FrameworkPropertyMetadata(0, callback);
md.BindsTwoWayByDefault = true;
md.DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged;
ValueProperty = DependencyProperty.Register(nameof(Value), typeof(int), typeof(QuadStateSelector), md);
DefaultStyleKeyProperty.OverrideMetadata(typeof(QuadStateSelector), new FrameworkPropertyMetadata(typeof(QuadStateSelector)));
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public int Value
{
get { return (int)this.GetValue(ValueProperty); }
set { this.SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty;
如您所见,默认绑定是2种方式,在更改源时触发。我还添加了一个回调,以便可以在属性更改时看到它。
我的XAML是:
<rt:QuadStateSelector Name="qss" Value="{Binding LineState}" Canvas.Left="262" Canvas.Top="10" Background="Azure"/>
<xctk:IntegerUpDown Value="{Binding ElementName=qss, Path=Value }"/>
我的消息来源是:
public int LineState
{
get => _LineState;
set => _LineState = value; // This line is never called
}
对依赖项属性值的更改是由控件模板中的事件触发器进行的,如下所示:
<Style TargetType="{x:Type local:QuadStateSelector}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:QuadStateSelector}">
<StackPanel Orientation="Horizontal" Background="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}">
<Ellipse Margin="1,0,1,0" Name="Button1" Width="14" Height="14" Stroke="{Binding Button1Brush, RelativeSource={RelativeSource TemplatedParent}}" StrokeThickness="2" Fill="AntiqueWhite"/>
<Ellipse Margin="1,0,1,0" Name="Button2" Width="14" Height="14" Stroke="{Binding Button2Brush, RelativeSource={RelativeSource TemplatedParent}}" StrokeThickness="2" Fill="AntiqueWhite"/>
<Ellipse Margin="1,0,1,0" Name="Button3" Width="14" Height="14" Stroke="{Binding Button3Brush, RelativeSource={RelativeSource TemplatedParent}}" StrokeThickness="2" Fill="AntiqueWhite"/>
<Ellipse Margin="1,0,1,0" Name="Button4" Width="14" Height="14" Stroke="{Binding Button4Brush, RelativeSource={RelativeSource TemplatedParent}}" StrokeThickness="2" Fill="AntiqueWhite"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="Value" Value="0">
<Setter TargetName="Button1" Property="Fill" Value="{Binding Button1Brush, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Trigger Property="Value" Value="1">
<Setter TargetName="Button2" Property="Fill" Value="{Binding Button2Brush, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Trigger Property="Value" Value="2">
<Setter TargetName="Button3" Property="Fill" Value="{Binding Button3Brush, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Trigger Property="Value" Value="3">
<Setter TargetName="Button4" Property="Fill" Value="{Binding Button4Brush, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<EventTrigger RoutedEvent="Control.MouseDown" SourceName="Button1">
<BeginStoryboard>
<Storyboard>
<Int32AnimationUsingKeyFrames Storyboard.TargetProperty="Value" Duration="0:0:1">
<DiscreteInt32KeyFrame KeyTime="0" Value="0"/>
</Int32AnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Control.MouseDown" SourceName="Button2">
<BeginStoryboard>
<Storyboard>
<Int32AnimationUsingKeyFrames Storyboard.TargetProperty="Value" Duration="0:0:1">
<DiscreteInt32KeyFrame KeyTime="0" Value="1"/>
</Int32AnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Control.MouseDown" SourceName="Button3">
<BeginStoryboard>
<Storyboard>
<Int32AnimationUsingKeyFrames Storyboard.TargetProperty="Value" Duration="0:0:1">
<DiscreteInt32KeyFrame KeyTime="0" Value="2"/>
</Int32AnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Control.MouseDown" SourceName="Button4">
<BeginStoryboard>
<Storyboard>
<Int32AnimationUsingKeyFrames Storyboard.TargetProperty="Value" Duration="0:0:1">
<DiscreteInt32KeyFrame KeyTime="0" Value="3"/>
</Int32AnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
有两个相互连接的控件,当我运行该应用程序时,一个控件中的更改会反映在另一个控件中,但是只有IntegerUpDown中所做的更改才会触发设置程序。因此,事件触发器肯定是在修改依赖项属性,因为(a)调用了属性已更改的回调,并且(b)IntegerUpDown(绑定到依赖项属性)中的值已更新。
我在这里想念什么?