如何发送验证消息表单模型以在 MVVM 模式中查看?

Posted

技术标签:

【中文标题】如何发送验证消息表单模型以在 MVVM 模式中查看?【英文标题】:How to do I send validation messages form model to view in the MVVM pattern? 【发布时间】: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
    

【问题讨论】:

【参考方案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 中的源对象集合:-)

【讨论】:

以上是关于如何发送验证消息表单模型以在 MVVM 模式中查看?的主要内容,如果未能解决你的问题,请参考以下文章

如何发送纯 JSON 对象(位于模型对象内)以在 Spring Boot 中查看?

Django使用不完整的模型创建一个有效的ModelForm,以在表单验证后手动添加字段

我如何传递从另一个模型获取的角色数组以在 laravel 中注册表单

PHP 电子邮件表单以在网页上发送消息

如何在Prism框架中的模块之间正确发送事件消息?

Drupal 查看 Ajax 块验证消息