WPF MVVM依赖项属性绑定不起作用



我在TextBox控件中使用beavior通过正则表达式过滤输入。为此,我添加了一个依赖属性来获取regex值。当我直接在xaml中设置值时,它可以正常工作,但当我试图用绑定属性传递它时,regex值不会在dependency属性中设置:

public class TextBoxInputRegExBehaviour : Behavior<TextBox>
{
public static readonly DependencyProperty RegularExpressionProperty =
DependencyProperty.Register("RegularExpression", typeof(string), typeof(TextBoxInputRegExBehaviour), new FrameworkPropertyMetadata(".*"));
public string RegularExpression
{
get { return (string)GetValue(RegularExpressionProperty); 
set { SetValue(RegularExpressionProperty, value); }
}
... 
}

当使用这种格式时,没有问题:

<TextBox Text="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Style="{StaticResource ValidableTextBox}">
<i:Interaction.Behaviors>
<behaviours:TextBoxInputRegExBehaviour RegularExpression="[0-9.]+$" />
</i:Interaction.Behaviors>
</TextBox>

但不使用绑定:

<TextBox Text="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Style="{StaticResource ValidableTextBox}">
<i:Interaction.Behaviors>
<behaviours:TextBoxInputRegExBehaviour RegularExpression="{Binding MyRegExString}" />
</i:Interaction.Behaviors>
</TextBox>

我做错了什么?

由于Behavior<T>不扩展FrameworkElement,因此它没有DataContext。可以使用Binding.RelativeSource遍历可视化树以查找下一个父FrameworkElement(及其DataContext属性(。

或者实现附加的bahavior(基于附加的属性(
由于附加的属性通常附加到FrameworkElement,因此您可以始终绑定到附加元素的DataContext(这是您自然会做的(
您可以通过在回调中检查附加元素的类型来强制执行类型约束,并在必要时抛出异常。

附加的行为使用示例

<TextBox TextBoxInputRegExBehaviour.IsEnabled="True" 
TextBoxInputRegExBehaviour.RegularExpression="{Binding MyRegExString}"
Text="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" 
Style="{StaticResource ValidableTextBox}" />

TextBoxInputRegExBehavior.cs
附加行为的实现

public class TextBoxInputRegExBehaviour : DependencyObject
{
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached(
"IsEnabled", 
typeof(bool), 
typeof(TextBoxInputRegExBehaviour), 
new FrameworkPropertyMetadata(default(bool), OnIsEnabledChanged));

public static void SetIsEnabled(DependencyObject attachingElement, bool value)
=> attachingElement.SetValue(IsEnabledProperty, value);
public static bool GetIsEnabled(DependencyObject attachingElement)   
=> (bool)attachingElement.GetValue(IsEnabledProperty);
public static readonly DependencyProperty RegularExpressionProperty =
DependencyProperty.RegisterAttached(
"RegularExpression", 
typeof(string), 
typeof(TextBoxInputRegExBehaviour), 
new FrameworkPropertyMetadata(".*", OnRegularExpressionChanged));

public static void SetRegularExpression(DependencyObject attachingElement, string value)
=> attachingElement.SetValue(RegularExpressionProperty, value);
public static string GetRegularExpression(DependencyObject attachingElement)   
=> (string)attachingElement.GetValue(RegularExpressionProperty);
private static void OnIsEnabledChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e) 
{
// Prior to C# 9: if (!(attachingElement is TextBox textBox))
if (attachingElement is not TextBox textBox)
{
// Optionally throw an exception if this makes sense
return;
}
if ((bool)e.NewValue)
{
// TODO::Handle behavior enabled, 
// for example subscribe to events of the TextBox instance
}
else
{
// TODO::Handle behavior disabled, 
// for example unsubscribe from events of the TextBox instance
}
}
private static void OnRegularExpressionChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e) 
{
// Prior to C# 9: if (!(attachingElement is TextBox textBox))
if (attachingElement is not TextBox textBox)
{
// Optionally throw an exception if this makes sense
return;
}

// TODO::Handle the changed RegularExpression value
}

... 
}

最新更新