如何避免使用额外的附加属性?

问题描述 投票:1回答:1

我具有2个属性的附加行为。 Here是我正在尝试做的,因为这个问题的详细信息是可选的。

第一个用于启用/禁用行为:

public static bool GetEnableHasErrors(DependencyObject obj) => (bool)obj.GetValue(EnableHasErrorsProperty);
public static void SetEnableHasErrors(DependencyObject obj, bool value) => obj.SetValue(EnableHasErrorsProperty, value);

public static readonly DependencyProperty EnableHasErrorsProperty =
    DependencyProperty.RegisterAttached("EnableHasErrors", typeof(bool), typeof(Behaviors), new PropertyMetadata((d, e) =>
    {
        var element = d as FrameworkElement;
        if (element == null)
            throw new ArgumentException("Only used with FrameworkElement");
        var handler = new RoutedEventHandler((s, a) => { ... }); // logic to set value of HasErrorsProperty attached property on element
        if ((bool)e.NewValue)
            element.SomeRoutedEvent += handler;
        else
            element.SomeRoutedEvent -= handler;
    }));

第二个用于将结果传递出去:

public static bool GetHasErrors(DependencyObject obj) => (bool)obj.GetValue(HasErrorsProperty);
public static void SetHasErrors(DependencyObject obj, bool value) => obj.SetValue(HasErrorsProperty, value);

public static readonly DependencyProperty HasErrorsProperty =
    DependencyProperty.RegisterAttached("HasErrors", typeof(bool), typeof(Behaviors));

并且此结果可以通过常规绑定进入视图模型或在视图中使用,无论如何:

<Grid local:Behaviors.EnableHasErrors="True"
      local:Behaviors.HasErrors="{Binding HasErrors, Mode=OneWayToSource}" >

感觉不对,为此我需要2个依赖项属性。可以只使用一个吗?我不能以某种方式推断内部行为通过绑定集启用的逻辑吗?这还不够吗?

我尝试使用BindingBase类型的单个属性,失败,发现my own question和此duplicate的答案不满意,所以BindingBase对我来说是错的。

想法?

c# wpf mvvm attached-properties attachedbehaviors
1个回答
2
投票

我不知道有什么方法可以避免针对您的特定情况。

对于这样的更复杂的行为,使用附加行为可能会很有用。附加行为具有在附加或分离行为时调用的方法,您可以使用这些方法来订阅事件/从事件中取消订阅。但是,它们的使用要冗长得多。

例如:

public class ErrorsBehavior : Behavior<FrameworkElement>
{
    public bool HasErrors
    {
        get => (bool )this.GetValue(HasErrorsProperty);
        set => this.SetValue(HasErrorsProperty, value);
    }
    public static readonly DependencyProperty HasErrorsProperty =
        DependencyProperty.Register(nameof(HasErrors), typeof(bool), typeof(ErrorsBehavior ), new PropertyMetadata(false));

    protected override void OnAttached()
    {
        AssociatedObject.SomeRoutedEvent += ...
    }

    protected override void OnDetaching()
    {
        AssociatedObject.SomeRoutedEvent -= ...
    }
}

用法将类似于:

<Grid>
    <i:Interaction.Behaviors>
        <my:ErrorsBehavior HasErrors="{Binding HasErrors, Mode=OneWayToSource}"/>
    </i:Interaction.Behaviors>
</Grid>

以前这些仅在专门安装了“ .NET的Visual Studio SDK混合版”组件(Visual Studio 2017)时可用,但现在在Microsoft.Behaviors.Xaml.Wpf NuGet包中可用。


[如果您具有双向绑定,并且绑定类型比bool(例如object)更复杂,则可以采取以下技巧:

public static class MyExtensions
{
    private static readonly object initialBindingTarget = new object();

    public static object GetSomething(DependencyObject obj) => obj.GetValue(SomethingProperty);

    public static void SetSomething(DependencyObject obj, object value) => obj.SetValue(SomethingProperty, value);

    public static readonly DependencyProperty SomethingProperty =
        DependencyProperty.RegisterAttached(
            "Something",
            typeof(object),
            typeof(MyExtensions),
            new FrameworkPropertyMetadata(
                initialBindingTarget,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (d, e) =>
        {
            // Trick to see if this is the first time we're set
            if (e.OldValue == initialBindingTarget)
            {
                // Do your first-time initialisation here
            }
        }));
}

这使用前哨初始值initialBindingTarget,并检查绑定何时将其更改为远离此值。

© www.soinside.com 2019 - 2024. All rights reserved.