【问题标题】:Data Validation in Silverlight 4Silverlight 4 中的数据验证
【发布时间】:2011-03-12 13:56:38
【问题描述】:

我可以控制 SL4。我想在按钮单击时进行数据验证。大问题通常是 SL4 使用绑定属性进行验证。

类似本例中给出的示例

http://weblogs.asp.net/dwahlin/archive/2010/08/15/validating-data-in-silverlight-4-applications-idataerrorinfo.aspx

<TextBox Text="{Binding Name,Mode=TwoWay,ValidatesOnDataErrors=true}" 
    Height="23" 
    Width="120"
    HorizontalAlignment="Left" 
    VerticalAlignment="Top"    />

但我想显示这样的错误消息 ....

使用我自己的代码,例如单击按钮我检查 (textbox1.text == null ) 然后将这种错误样式设置为 textbox1

【问题讨论】:

  • 文章作者答应解释INotifyDataErrorInfo,但可能他忘记了。这篇文章解释了为什么最新的验证接口更好:outcoldman.ru/en/blog/show/260

标签: silverlight validation silverlight-4.0


【解决方案1】:

延迟验证的一种方法是在绑定中设置属性UpdateSourceTrigger=Explicit。如果您这样做,绑定将不会更新源对象,因此不会导致验证错误,直到您明确告诉绑定这样做。单击按钮时,您会强制更新绑定,对每个控件使用如下行:

someTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();

然后,您的属性设置器会针对无效数据抛出异常。

如果有很多控件可以强制绑定更新,这种方法可能会有点麻烦。

此外,强制更新绑定必须在控件的代码隐藏中完成。如果您也使用带有按钮的命令,那么您可能会遇到问题。按钮可以同时具有 Command 和 Click 事件处理程序,并且两者都会在单击按钮时执行,但我不知道发生这种情况的顺序,或者即使可以保证顺序。一个快速的实验表明事件处理程序是在命令之前执行的,但我不知道这是否是未定义的行为。因此,该命令可能会在绑定更新之前被触发。


以编程方式创建验证工具提示的一种方法是绑定文本框的另一个属性,然后故意导致此绑定出错。

'sapient'posted a complete solution, including code 在 Silverlight 论坛上(搜索 2009 年 7 月 8 日下午 4:56 的帖子)。简而言之,他/她创建一个具有 getter 引发异常的属性的辅助对象,将文本框的 Tag 属性绑定到此辅助对象,然后强制更新绑定。

'sapient 的代码是在 Silverlight 4 发布之前编写的。我们会将他/她的代码“升级”到 Silverlight 4。ControlValidationHelper 类变为以下内容:

public class ControlValidationHelper : IDataErrorInfo
{
    public string Message { get; set; }

    public object ValidationError { get; set; }

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get { return Message; }
    }
}

很容易敲出一个快速演示应用程序来尝试一下。我创建了以下三个控件:

    <TextBox x:Name="tbx" Text="{Binding Path=Text, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Mode=TwoWay}" />
    <Button Click="ForceError_Click">Force error</Button>
    <Button Click="ClearError_Click">Clear error</Button>

Text 属性和两个按钮的事件处理程序位于代码隐藏中,如下所示:

    public string Text { get; set; }

    private void ForceError_Click(object sender, RoutedEventArgs e)
    {
        var helper = new ControlValidationHelper() { Message = "oh no!" };
        tbx.SetBinding(Control.TagProperty, new Binding("ValidationError")
        {
            Mode = BindingMode.TwoWay,
            NotifyOnValidationError = true,
            ValidatesOnDataErrors = true,
            UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
            Source = helper
        });
        tbx.GetBindingExpression(Control.TagProperty).UpdateSource();
    }

    private void ClearError_Click(object sender, RoutedEventArgs e)
    {
        BindingExpression b = tbx.GetBindingExpression(Control.TagProperty);
        if (b != null)
        {
            ((ControlValidationHelper)b.DataItem).Message = null;
            b.UpdateSource();
        }
    }

“强制错误”按钮应使验证错误出现在文本框上,“清除错误”按钮应使其消失。

如果您使用的是ValidationSummary,则会出现这种方法的一个潜在缺点。 ValidationSummary 将列出所有针对 ValidationError 的验证错误,而不是针对每个属性的名称。

【讨论】:

    【解决方案2】:

    虽然我的回答不被认为是可取的,但我仍然确信 MVVM 模式是执行验证的最佳选择。

    在我的代码中,您应该使用来自 this post about validation 的模型验证器和任何 mvvm 框架,例如 MVVM Light。

    使用视图模型和模型验证器类添加验证规则要容易得多:

    public class PersonViewModel : ViewModelBase, INotifyDataErrorInfo
    {
        private ModelValidator _validator = new ModelValidator();
    
        public PersonViewModel()
        {
            this._validator.AddValidationFor(() => this.Age)
                .Must(() => this.Age > 0)
                .Show("Age must be greater than zero");
        }
    }
    

    当且仅当用户明确点击按钮时,您才能验证模型:

        #region INotifyDataErrorInfo
    
        public IEnumerable GetErrors(string propertyName)
        {
            return this._validator.GetErrors(propertyName);
        }
    
        public bool HasErrors
        {
            get { return this._validator.ErrorMessages.Count > 0; }
        }
    
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged = delegate { };
    
        protected void OnErrorsChanged(string propertyName)
        {
            ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
            this.RaisePropertyChanged("HasErrors");
        }
        #endregion
    
        public bool Validate()
        {
            var result = this._validator.ValidateAll();
            this._validator.PropertyNames.ForEach(OnErrorsChanged);
            return result;
        }
    

    大家都看到了,这里没有什么难的,20-30行代码就行了。

    此外,MVVM 方法更加灵活,您可以在多个视图模型中重复使用一些常见的验证场景。

    【讨论】:

      猜你喜欢
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      • 2011-04-19
      • 1970-01-01
      相关资源
      最近更新 更多