我有一个小型测试WPF MVVM应用程序,其中一个视图允许用户更改客户的名字或姓氏,全名自动更改,因此通信从M到MV到 - V和背部,一切都完全解耦,到目前为止一直很好。
但是现在我想看看我将如何开始扩展这个以使用MVVM模式构建大型应用程序,我发现解耦成为一个障碍,即:
我将如何进行验证消息,例如如果回到LastName setter中的模型中,我添加的代码可以防止设置超过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
}
}
答案 0 :(得分:6)
要进行验证,请让您的视图模型实现IDataErrorInfo
。至于视图之间的通信,不要害怕编写UI服务(例如,允许和查看模型以提供将在UI中某处显示的消息的消息服务)。或者,如果视图模型之间存在硬关系(例如,一个视图模型拥有另一个视图模型),则拥有视图模型可以保存对子视图模型的引用。
答案 1 :(得分: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设置为视图的datacontext:
namespace xxx
{
public partial class ViewClass: UserControl
{
public ViewClass()
{
InitializeComponent();
this.DataContext = new ViewClass_ViewModel();
}
}
}
Bingo - 将完美的工作验证推送到任何关注订阅此ViewModel / Property的视图。
答案 2 :(得分:0)
您还可以将验证绑定到SL3中的源对象集合: - )