Я не знаю ни одного способа избежать этого для вашего конкретного случая.
Для более сложных вариантов поведения, подобных этому, может быть полезно использовать прикрепленное поведение. Прикрепленные поведения имеют методы, которые вызываются, когда поведение присоединяется или отсоединяется, и которые можно использовать для подписки на события или отписки от них. Однако они значительно более многословны в использовании.
Например:
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>
Они раньше были доступны, только есливы специально установили компонент «Blend for Visual Studio SDK для .NET» (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
}
}));
}
При этом используетсяначальное значение Sentinel initialBindingTarget
, и проверяет, когда привязка изменяет значение с этого.