WPF TextBox MaxLength——是否有任何方法将其绑定到绑定字段上的数据验证最大长度

本文关键字:绑定 数据 验证 字段 是否 TextBox 任何 方法 WPF MaxLength | 更新日期: 2023-09-27 18:19:36

ViewModel:

public class MyViewModel
{
    [Required, StringLength(50)]
    public String SomeProperty { ... }
}

XAML:

<TextBox Text="{Binding SomeProperty}" MaxLength="50" />

是否有任何方法可以避免将TextBox的MaxLength设置为与我的ViewModel匹配(由于它在不同的程序集中,因此可能会发生变化),并让它根据StringLength要求自动设置最大长度?

WPF TextBox MaxLength——是否有任何方法将其绑定到绑定字段上的数据验证最大长度

我使用Behavior将TextBox连接到其绑定属性的验证属性(如果有的话)。行为看起来像这样:

/// <summary>
/// Set the maximum length of a TextBox based on any StringLength attribute of the bound property
/// </summary>
public class RestrictStringInputBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        AssociatedObject.Loaded += (sender, args) => setMaxLength();
        base.OnAttached();
    }
    private void setMaxLength()
    {
        object context = AssociatedObject.DataContext;
        BindingExpression binding = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
        if (context != null && binding != null)
        {
            PropertyInfo prop = context.GetType().GetProperty(binding.ParentBinding.Path.Path);
            if (prop != null)
            {
                var att = prop.GetCustomAttributes(typeof(StringLengthAttribute), true).FirstOrDefault() as StringLengthAttribute;
                if (att != null)
                {
                    AssociatedObject.MaxLength = att.MaximumLength;
                }
            }
        }
    }
}

您可以看到,该行为只是检索文本框的数据上下文及其"text"的绑定表达式。然后它使用反射来获得"StringLength"属性。用法如下:

<UserControl
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    <TextBox Text="{Binding SomeProperty}">
        <i:Interaction.Behaviors>
            <local:RestrictStringInputBehavior />
        </i:Interaction.Behaviors>
    </TextBox>
</UserControl>

您也可以通过扩展TextBox来添加此功能,但我喜欢使用行为,因为它们是模块化的。

虽然我不会完全自己写代码,但有一个想法是创建自己的MarkupExtension,它将采用属性名称,并在寻找StringLengthAttribute时进行反思。

如果该属性存在,请尝试将目标绑定到该值(使用反射)。如果没有,则将0绑定到目标值(0是默认值,即没有最大值)。

一种方法是在同一视图模型中创建一个名为SomePropertyMaxLength的属性,然后将MaxLength属性绑定到该属性。
<TextBox Text="{Binding SomeProperty}" MaxLength="{Binding SomePropertyMaxLength}"/>

Markup扩展无疑是最好的选择。我正在创建BindingDecoratorBase的一个子类,名为Binding,它具有模型DataType依赖属性。由于MarkupExtensions是在InitializeComponent()期间创建的,因此无法确定DataContext,因为它尚未设置。

提供模型类型允许对模型上定义的属性进行反射访问。这允许:

  • 正在设置文本框的最大长度
  • 设置文本块的StringFormat
  • 根据成员数据类型设置默认转换器
  • 正在添加所需的验证。使用绑定的ValidationRules或设置ValidatesDataErrors

标记看起来像:Text="{PO:Binding DataType=model:modAccount,Path=SubAccount}"

Formatting、MaxLength和Conversion集成到一个包中,无需随着模型类的变化而进行任何更改。

或者您可以让您的模型只接受最大#chars:

private string _MyText { get; set; }
public string MyText { get => _MyText; set => _MyText = value?.Substring(0, 
Math.Min(value.Length, 15)); }
Text="{Binding Path=MyText}"