1

我的应用程序使用 MVVM 模式。MyTextBox绑定到我的 ViewModel 的属性(类型字符串)。

TextBox通过用户键入更改的内容时,我想执行一些验证。

所以,目前,我的代码是

<TextBox Text="{Binding XmlContentAsString, UpdateSourceTrigger=PropertyChanged}" />

我的 ViewModel 有这个属性和字段:

        private string _xmlContentAsString;
        public string XmlContentAsString
        {
            get { return _xmlContentAsString; }
            set
            {
                if (_xmlContentAsString == value)
                    return;

                _xmlContentAsString = value;
                PerformValidiationLogic(value);//This is where I am unsure
            }
        }

现在,这行得通,但是,我不知道为什么,我不喜欢这个!将方法包含在属性中有些感觉“被黑客入侵”。

有人可以告诉我这是否是使用 MVVM 模式时的正确方法吗?

4

4 回答 4

1

在您的示例中,您对值执行验证逻辑,但如果验证失败,验证的结果是什么?通常,您希望通知用户验证失败。如果是这种情况,那么我建议 IDataErrorInfo (示例可以在这里找到:

http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/)。

如果您打算在不通知用户的情况下覆盖该值,那么在 setter 中进行验证是可以接受的(尽管出于更多个人原因仍然不是粉丝)。

于 2013-04-10T18:01:12.173 回答
1

有不同类型的验证。对于简单的验证字符串长度或允许的字符等,您可以使用 DataAnnotations 并将验证放在属性的属性中。您需要使用 System.ComponentModel.DataAnnotations;

然后例如将字符串保持为 9 个字符:

    [StringLength(9)]
    public string StringValue
    {
        get
        {
            return stringValue;
        }

        set
        {
            this.stringValue = value;
        }
    }

然后是更复杂的验证,并且有效地执行您的业务逻辑。关于如何做到这一点似乎有很多观点。理想情况下,它应该属于模型,以便可以重用验证,但显然是通过视图模型调用的。

就我个人而言,我偶尔会在属性设置器中调用方法,对我来说,这就是能够创建设置器和获取器的全部原因 - 否则除了自动属性之外没有任何意义。

但是,如果它是复杂的或异步的,那么您可能会遇到问题。我会非常小心地使用 UpdateSourceTrigger=PropertyChanged,因为这意味着您将在每个角色中触发它。

于 2013-04-10T17:18:34.973 回答
0

在我看来,这是正确的做法。我将为您的 ViewModel 编写一个基类,其中包含一个设置属性的方法,调用 PropertyChanged 并验证是否将某些验证规则附加到该属性。

例如:

public abstract class ValidableViewModel
{
    private List<ValidationRule> _validationRules;

    public ValidableViewModel()
    {
        _validationRules = new List<ValidationRule>();
    }

    protected virtual void SetValue<T, T2>(Expression<Func<T>> expression,
                                           ref T2 backend, T2 value)
    {
        if (EqualityComparer<T2>.Default.Equals(backend, value))
            return;

        backend = value;
        OnPropertyChanged(expression);

        Validate(expression.Name, value);
    }

    protected void Validate(string propertyName, object value)
    {
        foreach(var validationRule in _validationRules)
        {
            if(validationRule.PropertyName == propertyName)
                validationRule.Execute(value);
        }
    }
}

代码不完整,有很多遗漏。但这可能是一个开始;-)

于 2013-04-10T11:06:25.027 回答
0

我个人不建议在您的财产中添加太多逻辑。我会使用绑定到事件的命令,即文本框的 lostfocus 事件,并在那里执行您的验证。

我会使用这样的东西:

 <TextBox Text="{Binding XmlContentAsString, UpdateSourceTrigger=PropertyChanged}">
        <interactivity:Interaction.Triggers>
            <interactivity:EventTrigger EventName="LostFocus">
                <interactivity:InvokeCommandAction Command="{Binding LostFocusCommand, Mode=OneWay}"/>
            </interactivity:EventTrigger>
        </interactivity:Interaction.Triggers>           
    </TextBox>

然后在您的视图模型中有一个带有验证逻辑的 LostFocusCommand 命令。
我使用 mvvm-light 并且可以为此提供更详细的示例。(您需要在 xaml 顶部包含混合交互声明)

于 2013-04-10T16:03:59.777 回答