我在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
}
...
}