WPF中的可重复模式

时间:2018-11-12 03:24:27

标签: c# wpf xaml data-binding

我正在尝试在WPF中实现相当特定的目标。我需要创建一个可验证的控件,该控件将被绑定到像这样的通用类的对象上

public interface IVerifiable
{
    bool Verified { get; set; }
}

public class VerifiableProperty<T> : INotifyPropertyChanged, IVerifiable
{
    private T _value;
    private bool _verified;

    public T Value
    {
        get => _value;
        set
        {
            if (Equals(value, _value)) return;
            _value = value;
            OnPropertyChanged();
        }
    }

    public bool Verified
    {
        get => _verified;
        set
        {
            if (value == _verified) return;
            _verified = value;
            OnPropertyChanged();
        }
    }
}

我以此方式绑定控件

<TextBox Text="{Binding Path=Number.Value}" att:VerifiableControl.Verified="{Binding Path=Number.Verified}"
                                                 BorderBrush="{Binding Path=(att:VerifiableControl.Verified), Mode=OneWay,
                                                               Converter={StaticResource BackColorVerifiedConverter}}">
                                            <inter:Interaction.Triggers>
                                                <inter:EventTrigger EventName="LostFocus">
                                                    <inter:InvokeCommandAction Command="{Binding Path=DataContext.VerifyCurrentFieldCommand, ElementName=Root}"
                                                                               CommandParameter="{Binding Path=Number}"/>
                                                </inter:EventTrigger>
                                            </inter:Interaction.Triggers>
                                        </TextBox>

Verifiable属性对象的通用值绑定到文本(如果使用DatePicker等,则绑定到SelectedDate等),边框颜色通过转换器绑定到标志“ Verified”,并且还将“ FocusLost”事件的交互触发器绑定到ViewModel命令,将相应属性对象的“已验证”标志设置为true。

我真的不喜欢这样的想法,我必须在几乎没有任何更改的情况下多次粘贴此块。我知道,我无法在样式中添加触发触发器,也找不到另一种方式来制作某种短模式。 因此,是否有办法为此xaml代码创建某种短模式,以便我可以自定义要绑定的属性名称?或者,也许您可​​以为我想要实现的目标建议另一种方法?

1 个答案:

答案 0 :(得分:1)

使用一些附加属性,并将其附加到LostFocus事件。

public static class VerifiableBehaviour
{
    public static bool GetVerified(UIElement obj) => (bool)obj.GetValue(VerifiedProperty);
    public static void SetVerified(DependencyObject obj, bool value) => obj.SetValue(VerifiedProperty, value);

    public static readonly DependencyProperty VerifiedProperty = DependencyProperty.RegisterAttached(
        "Verified", typeof(bool), typeof(VerifiableBehaviour),
        new FrameworkPropertyMetadata(false)
        {
            BindsTwoWayByDefault = true,
            DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
        });

    public static bool GetTracking(UIElement obj) => (bool)obj.GetValue(TrackingProperty);
    public static void SetTracking(UIElement obj, bool value) => obj.SetValue(TrackingProperty, value);

    public static readonly DependencyProperty TrackingProperty = DependencyProperty.RegisterAttached(
        "Tracking", typeof(bool), typeof(VerifiableBehaviour),
        new PropertyMetadata(false, Tracking_PropertyChanged));

    private static void Tracking_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UIElement element = d as UIElement;

        if ((bool)e.NewValue)
            element.LostFocus += Element_LostFocus;
        else
            element.LostFocus -= Element_LostFocus;
    }

    private static void Element_LostFocus(object sender, RoutedEventArgs e)
    {
        UIElement element = sender as UIElement;
        SetVerified(element, true);
    }
}

并将其绑定到您的控件

<StackPanel>
    <StackPanel.Resources>
        <DataTemplate x:Key="VerifiableText">
            <StackPanel>
                <TextBox b:VerifiableBehaviour.Tracking="True" 
                         b:VerifiableBehaviour.Verified="{Binding Verified}" 
                         Text="{Binding Value}"/>
                <TextBlock>(Verified: <Run Text="{Binding Verified}"/>)</TextBlock>
            </StackPanel>
        </DataTemplate>
    </StackPanel.Resources>

    <TextBlock Text="MyProperty1"/>
    <ContentControl ContentTemplate="{StaticResource VerifiableText}" 
                    Content="{Binding MyProperty1}" IsTabStop="False"/>
    <Separator/>
    <TextBlock Text="MyProperty2"/>
    <ContentControl ContentTemplate="{StaticResource VerifiableText}" 
                    Content="{Binding MyProperty2}" IsTabStop="False"/>
    <Separator/>
    <TextBlock Text="MyProperty3"/>
    <ContentControl ContentTemplate="{StaticResource VerifiableText}" 
                    Content="{Binding MyProperty3}" IsTabStop="False"/>
    <Separator/>
    <TextBlock Text="MyProperty4"/>
    <ContentControl ContentTemplate="{StaticResource VerifiableText}" 
                    Content="{Binding MyProperty4}" IsTabStop="False"/>
    <Separator/>
</StackPanel>