【问题标题】:How to do I send validation messages form model to view in the MVVM pattern?如何发送验证消息表单模型以在 MVVM 模式中查看?
【发布时间】:2009-04-03 08:48:59
【问题描述】:

我有一个小型测试 WPF MVVM 应用程序在其中工作,其中一个视图允许用户更改客户的名字或姓氏,并且全名会自动更改,因此通信是从 M 到 MV 到 - V 和回来,一切都完全解耦,到目前为止一切顺利。

但是现在当我考虑如何开始扩展它以使用 MVVM 模式构建大型应用程序时,我发现解耦是一个障碍,即:

  • 我将如何处理验证消息,例如如果回到 LastName 设置器中的模型中,我添加了阻止设置超过 50 个字符的名称的代码,如何向视图发送消息,告诉它显示名称太长的消息?

  • 在复杂的应用程序中我可能在一个屏幕上同时有几十个视图,但我知道在 MVVM 中每个视图都有一个且只有一个 ViewModel 分配给它以提供它数据和行为,因此视图如何相互交互,例如在上面的验证示例中,如果回到客户模型中,我们想要通知特定的“MessageAreaView”以显示消息“姓氏可能只包含 50 个字符。”,我们如何将堆栈向上传达给该特定视图?

CustomerHeaderView.xaml(视图):

<UserControl x:Class="TestMvvm444.Views.CustomerHeaderView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <StackPanel HorizontalAlignment="Left">
            <ItemsControl ItemsSource="{Binding Path=Customers}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <StackPanel Orientation="Horizontal">
                                <TextBox
                                Text="{Binding Path=FirstName, Mode=TwoWay}" 
                                Width="100" 
                                Margin="3 5 3 5"/>
                                <TextBox 
                                Text="{Binding Path=LastName, Mode=TwoWay}" 
                                Width="100"
                                Margin="0 5 3 5"/>
                                <TextBlock 
                                Text="{Binding Path=FullName, Mode=OneWay}" 
                                Margin="0 5 3 5"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </Grid>
</UserControl>

Customer.cs(模型):

using System.ComponentModel;

namespace TestMvvm444.Model
{
    class Customer : INotifyPropertyChanged
    {

        public int ID { get; set; }
        public int NumberOfContracts { get; set; }

        private string firstName;
        private string lastName;

        public string FirstName
        {
            get { return firstName; }
            set
            {
                if (firstName != value)
                {
                    firstName = value;
                    RaisePropertyChanged("FirstName");
                    RaisePropertyChanged("FullName");

                }
            }
        }

        public string LastName
        {
            get { return lastName; }
            set
            {
                if (lastName != value)
                {
                    lastName = value;
                    RaisePropertyChanged("LastName");
                    RaisePropertyChanged("FullName");
                }
            }
        }

        public string FullName
        {
            get { return firstName + " " + lastName; }
        }



        #region PropertChanged Block
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
        #endregion
    }
}

【问题讨论】:

    标签: wpf validation mvvm


    【解决方案1】:

    为了验证,让您的视图模型实现IDataErrorInfo。至于视图之间的通信,不要害怕编写 UI 服务(例如,允许视图模型提供将在 UI 中某处显示的消息的消息服务)。或者,如果视图模型之间存在硬关系(例如,一个视图模型拥有另一个视图模型),那么拥有的视图模型可以持有对子视图模型的引用。

    【讨论】:

      【解决方案2】:

      添加验证消息的一个非常简单的方法是使用绑定。

      向您的视图模型添加一个可通知的属性,用于定义是否应显示验证消息:

      private Boolean _itemValidatorDisplayed;
      public Boolean ItemValidatorDisplayed
      {
          get { return _itemValidatorDisplayed; }
          set
          {
              _itemValidatorDisplayed= value;
              _OnPropertyChanged("ItemValidatorDisplayed");
          }
      }
      

      添加一个将 bool 转换为可见性的转换器类:

      using System;
      using System.Windows;
      
      namespace xxx
      {
          public class BoolToVisibilityConverter : IValueConverter
          {
              public bool Negate { get; set; }
      
              public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
              {
                  bool val = System.Convert.ToBoolean(value);
                  if (!Negate)
                  {
                      return val ? Visibility.Visible : Visibility.Collapsed;
                  }
                  else
                  {
                      return val ? Visibility.Collapsed : Visibility.Visible;
                  }
              }
      
              public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
              {
                  throw new NotImplementedException();
              }
          }
      }
      

      从视图绑定到属性并应用转换器:

          <UserControl x:Class="ViewClass"
          ...
          >
              <UserControl.Resources>
                  <contract:BoolToVisibilityConverter Negate="False"
                                                      x:Key="BoolToVisibilityConverter" />
              </UserControl.Resources>
      
      ...
      
      <TextBlock Visibility="{Binding Converter={StaticResource BoolToVisibilityConverter}, Path=ItemValidatorDisplayed}" />
      
      ...
      
      </UserControl>
      

      您需要将 ViewModel 设置为视图的数据上下文:

      namespace xxx
      {
          public partial class ViewClass: UserControl
          {
              public ViewClass()
              {
                  InitializeComponent();
      
                  this.DataContext = new ViewClass_ViewModel();
              }
      }
      }
      

      Bingo - 完美工作的验证被推送到任何愿意订阅此 ViewModel/Property 的视图。

      【讨论】:

        【解决方案3】:

        您还可以将验证绑定到 SL3 中的源对象集合:-)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-29
          • 1970-01-01
          • 1970-01-01
          • 2011-01-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多