视图模型:
public class MyViewModel
{
[Required, StringLength(50)]
public String SomeProperty { ... }
}
XAML:
<TextBox Text="{Binding SomeProperty}" MaxLength="50" />
有没有办法避免设置TextBox的MaxLength以匹配我的ViewModel(由于它在不同的程序集中可能会改变)并让它根据StringLength要求自动设置最大长度?
答案 0 :(得分:17)
我使用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
来添加此功能,但我喜欢使用行为,因为它们是模块化的。
答案 1 :(得分:1)
虽然我不打算完全自己编写代码,但有一个想法是创建自己的MarkupExtension
,它将获取属性名称并反映寻找StringLengthAttribute
。
如果属性存在,请尝试将目标绑定到该值(使用反射)。如果不是,则将0绑定到目标值(默认值为0,即无最大值)。
答案 2 :(得分:0)
一种方法是在同一个名为SomePropertyMaxLength的视图模型中创建一个属性,然后将MaxLength属性绑定到该属性。
<TextBox Text="{Binding SomeProperty}" MaxLength="{Binding SomePropertyMaxLength}"/>
答案 3 :(得分:0)
标记扩展绝对是最佳选择。 我正在创建一个名为Binding的BindingDecoratorBase的子类,它具有模型DataType依赖项属性。由于MarkupExtensions是在InitializeComponent()期间创建的,因此无法确定DataContext,因为它尚未设置。
提供模型类型允许对模型上定义的属性进行反射访问。 这允许:
标记看起来像: Text =&#34; {PO:Binding DataType = model:modAccount,Path = SubAccount}&#34;
格式化,MaxLength和转换汇总到一个包中,无需在模型类更改时更改任何内容。
答案 4 :(得分: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}"