我具有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
对我来说是错的。
想法?
我不知道有什么方法可以避免针对您的特定情况。
对于这样的更复杂的行为,使用附加行为可能会很有用。附加行为具有在附加或分离行为时调用的方法,您可以使用这些方法来订阅事件/从事件中取消订阅。但是,它们的使用要冗长得多。
例如:
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
,并检查绑定何时将其更改为远离此值。