WPF TextBox MaxLength - 有什么方法可以将其绑定到绑定字段上的数据验证最大长度吗?

发布于 2024-12-25 05:25:05 字数 360 浏览 3 评论 0原文

ViewModel:

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

XAML:

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

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

ViewModel:

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

XAML:

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

Is there any way to avoid setting the MaxLength of the TextBox to match up my ViewModel (which could change since it is in a different assembly) and have it automatically set the max length based on the StringLength requirement?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北风几吹夏 2025-01-01 05:25:05

我使用 行为 来连接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 来添加此功能,但我喜欢使用行为,因为它们是模块化的。

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.

趴在窗边数星星i 2025-01-01 05:25:05

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

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

While I'm not going to write the code out completely myself, one idea is to create your own MarkupExtension that will take the property name and reflect over looking for a StringLengthAttribute.

If the attribute exists, attempt to bind the target to that value (using reflection). If not, then bind 0 to the target value (0 is default, i.e. no max).

墨落画卷 2025-01-01 05:25:05

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

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

One way to do it would be to create a property in that same viewmodel called SomePropertyMaxLength and then bind the MaxLength property to that property.

<TextBox Text="{Binding SomeProperty}" MaxLength="{Binding SomePropertyMaxLength}"/>
隐诗 2025-01-01 05:25:05

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

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

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

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

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

The Markup extension is definitely the way to go.
I am creating a subclass of BindingDecoratorBase called Binding which has a model DataType dependency property. As MarkupExtensions are created during InitializeComponent() there is no way to determine the DataContext as it will not have been set yet.

Providing the model type permits reflective access to attributes defined on the model.
This permits:

  • Setting MaxLength for TextBoxes.
  • Setting StringFormat for TextBlocks.
  • Setting the default Converter depending on member data type.
  • Adding required validation. Using either the binding's ValidationRules or by setting ValidatesOnDataErrors.

The markup looks like:
Text="{PO:Binding DataType=model:modAccount, Path=SubAccount}"

Formatting, MaxLength, and Conversion rolled into one package with no need to change anything as the model classes change.

锦上情书 2025-01-01 05:25:05

或者您可以让您的模型仅接受最大 # 个字符:

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

Text="{Binding Path=MyText}"

Or you can have your model only to accept a max # 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}"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文