Я создаю пользовательский элемент управления и хочу добавить свойство зависимостей, которое работает как 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, приводят к срабатыванию установщика.Таким образом, триггеры событий определенно изменяют свойство зависимости, потому что (а) вызывается обратный вызов измененного свойства, и (б) значение в IntegerUpDown (привязанное к свойству зависимости) обновляется.
Что мне здесь не хватает?