C# WPF TextBox MaxLength——有没有办法将其绑定到绑定字段上的数据验证最大长度?

C# WPF TextBox MaxLength——有没有办法将其绑定到绑定字段上的数据验证最大长度?,c#,wpf,xaml,data-annotations,maxlength,C#,Wpf,Xaml,Data Annotations,Maxlength,视图模型: public class MyViewModel { [Required, StringLength(50)] public String SomeProperty { ... } } XAML: 有没有办法避免设置文本框的MaxLength以匹配我的ViewModel(因为它位于不同的程序集中,所以可能会发生更改)并根据StringLength要求自动设置最大长度?一种方法是在同一视图模型中创建一个名为SomePropertyMaxLength的属性,然后将M

视图模型:

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



有没有办法避免设置文本框的MaxLength以匹配我的ViewModel(因为它位于不同的程序集中,所以可能会发生更改)并根据StringLength要求自动设置最大长度?

一种方法是在同一视图模型中创建一个名为SomePropertyMaxLength的属性,然后将MaxLength属性绑定到该属性

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

虽然我不打算自己完整地编写代码,但有一个想法是创建您自己的,它将采用属性名称,并反思如何查找
StringLengthattAttribute

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

我使用了将文本框连接到其绑定属性的验证属性(如果有)。行为如下所示:

/// <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;
                }
            }
        }
    }
}
<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>
//
///根据绑定属性的任何StringLength属性设置文本框的最大长度
/// 
公共类RestrictStringInputBehavior:行为
{
受保护的覆盖无效附加()
{
AssociatedObject.Loaded+=(发送方,参数)=>setMaxLength();
base.onatached();
}
私有void setMaxLength()
{
对象上下文=AssociatedObject.DataContext;
BindingExpression binding=AssociatedObject.GetBindingExpression(TextBox.TextProperty);
if(上下文!=null&&binding!=null)
{
PropertyInfo prop=context.GetType().GetProperty(binding.ParentBinding.Path.Path);
如果(prop!=null)
{
var att=prop.GetCustomAttributes(typeof(StringLengthAttribute),true);
如果(att!=null)
{
AssociatedObject.MaxLength=att.MaximumLength;
}
}
}
}
}
您可以看到,该行为只是检索文本框的数据上下文,以及“text”的绑定表达式。然后它使用反射来获得“StringLength”属性。用法如下:

/// <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;
                }
            }
        }
    }
}
<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>

标记扩展肯定是一条路要走。
我正在创建名为Binding的BindingDecoratorBase的子类,该子类具有模型数据类型依赖属性。由于MarkupExtensions是在InitializeComponent()期间创建的,因此无法确定DataContext,因为它尚未设置

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

  • 设置文本框的最大长度
  • 设置文本块的StringFormat
  • 根据成员数据类型设置默认转换器
  • 添加所需的验证。使用绑定的ValidationRules或设置ValidatesOnDaerRors
标记看起来像: Text=“{PO:Binding DataType=model:modAccount,Path=SubAccount}”


格式设置、MaxLength和转换集成到一个软件包中,无需随着模型类的更改而更改任何内容。

或者,您可以让您的模型只接受max#chars:


是的,我考虑过这一点,但我真的想避免通过添加额外的属性来反映我的元数据,然后再通过我所有的xaml和绑定这些属性。。。我希望有一种“隐蔽”的方式。。。可能通过附加行为?您可以将“SomeProperty”更改为包含字符串值和maxlength值的对象,然后分别绑定到这些属性。这样,您就不必创建新属性,但仍需进行xaml更改。我花了很长时间试图找出如何编写此扩展,使其符合您的要求。应为“value.Length-1”