10

视图模型:

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

XAML:

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

有什么方法可以避免设置 TextBox 的 MaxLength 以匹配我的 ViewModel(由于它在不同的程序集中,它可能会改变)并让它根据 StringLength 要求自动设置最大长度?

4

5 回答 5

18

I used a Behavior to connect the TextBox to its bound property's validation attribute (if any). The behavior looks like this:

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

You can see, the behavior simply retrieves the data context of the text box, and its binding expression for "Text". Then it uses reflection to get the "StringLength" attribute. Usage is like this:

<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>

You could also add this functionality by extending TextBox, but I like using behaviors because they are modular.

于 2013-02-07T21:47:26.493 回答
1

虽然我不会自己完全编写代码,但一个想法是创建自己的MarkupExtension,它将获取属性名称并反映在寻找StringLengthAttribute.

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

于 2012-01-05T19:18:05.950 回答
0

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

<TextBox Text="{Binding SomeProperty}" MaxLength="{Binding SomePropertyMaxLength}"/>
于 2012-01-05T15:52:36.807 回答
0

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

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

  • 为文本框设置 MaxLength。
  • 为 TextBlock 设置 StringFormat。
  • 根据成员数据类型设置默认转换器。
  • 添加所需的验证。使用绑定的 ValidationRules 或通过设置 ValidatesOnDataErrors。

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

Formatting、MaxLength 和 Conversion 整合到一个包中,无需随着模型类的更改而更改任何内容。

于 2015-05-09T23:13:47.657 回答
0

或者你可以让你的模型只接受最大 # 字符:

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

Text="{Binding Path=MyText}"
于 2020-01-30T09:44:00.537 回答