官网:https://primslibrary.com
源码地址:https://guthub.com/PrismLibrary/prism
Prism是由微软发布、维护的开源框架,提供了一组设计模式的实现,有助于编写结构良好的且可维护的XAML应用程序,包括MVVM、依赖注入、命令、事件聚合器等。
关键程序集
Prism.Core
:实现MVVM的核心功能,是一个与平台无关的项目,可以在多个开发平台中使用(Prism.dll
)。
- 如果只需要实现MVVM中的一些简单功能、例如属性变化通知、命令等,只需要在Nuget中安装
Prism.Core
库即可。
Prism.Wpf
:包含了DialogService
、Region
、Module
、Navigation
和其他一些WPF功能,使得WPF开发更加方便快捷(Prism.Wpf.dll
)。
-
如果需要进一步使用WPF中的一些其他功能,可以在Nuget中安装
Prism.Wpf
库,由于Prism.Wpf
依赖于Prism.Core
因此,无需再安装Prism.Core
。
Prism.Unity
:包含Prism.Unity.Wpf.dll
、Prism.DryIoc.Wpf.dll
。
-
如果需要使用IOC,则需要安装
Prism.Unity
,由于Prism.Unity
依赖于Prism.Wpf
,因此不需要再安装Prism.Wpf
和Prism.Core
数据处理
一、属性变化通知
Prism框架提供了BindableBase
类,用于做数据处理(例如属性的变化通知等)。
五种属性变化通知方式
通过继承BindableBase
类,可以更加便捷地在WPF中实现属性变化通知,具体有如下五种方式。
其中前三种没啥特殊的,第四种方式可以在属性变化时,通知其他属性的绑定控件;而第五种方式则可以在属性发生变化后调用指定的函数。
public class MainViewModel : BindableBase
{
private string _value;
public string Value
{
get { return _value; }
set
{
// 第一种方式
SetProperty(ref _value, value);
// 第二种方式
//this.OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("Value"));
// 第三种方式
//this.RaisePropertyChanged();
// 第四种方式:可以通知另一个属性
//SetProperty(ref _value, value, "Var");
// 第五种方式
//SetProperty(ref _value, value, OnValueChanged);
}
}
private void OnValueChanged()
{
//属性成功变化后的执行函数
}
}
二、数据异常处理
Prism框架提供了ErrorsContainer<T>
类型专门用于处理项目中出现地异常。其中泛型T
为指定的异常消息类型。
1、INotifyDataErrorInfo接口
使用ErrorsContainer<T>
需要实现INotifyDataErrorInfo
接口。
实现INotifyDataErrorInfo
接口主要需要实现其中的三个成员,分别如下:
event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged
:事件属性成员,用于异常通知。
bool HasErrors
:属性成员,用于判断是否存在异常。
- 一般会通过
ErrorsContainer
对象的HasErrors
属性来进行判断。
IEnumerable GetErrors(string propertyName)
:方法成员,用于获取相关属性名称的异常。
- 一般会通过
ErrorsContainer
对象的GetErrors
方法来获得对应属性的异常。
public class MainViewModel :INotifyDataErrorInfo
{
//声明ErrorsContainer对象,这里没有定义,详细做法请看下文
public ErrorsContainer<string> _errorsContainer;
public bool HasErrors => _errorsContainer.HasErrors;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
return _errorsContainer.GetErrors(propertyName);
}
......
}
2、ErrorsContainer类
构造函数
ErrorsContainer<T>(Action<string> raiseErrorsChanged)
:创建ErrorsContainer
对象。
- raiseErrorsChanged:发生异常时的执行函数,函数中要去触发异常发生事件,也就是
INotifyDataErrorInfo
接口的ErrorsChanged
事件成员。
常用成员
bool HasErrors
:属性成员,用于判断当前是否存在异常。
IEnumerable<T> GetErrors(string propertyName)
:获取指定属性的异常集合。
- propertyName:要获取异常的属性名称。
SetErrors(string propertyName, IEnumerable<T> newValidationResults)
:设置异常(也就是发生异常了)。
- propertyName:触发异常的属性名称。
- newValidationResults:异常集合,可以是
string
数组,也可以是其他类型数组。
3、具体实现过程
异常处理编写
实现INotifyDataErrorInfo
接口
public class MainViewModel : INotifyDataErrorInfo
{
public bool HasErrors => throw new NotImplementedException();
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
throw new NotImplementedException();
}
}
定义ErrorsContainer<T>
对象属性,完善INotifyDataErrorInfo
成员实现
public class MainViewModel : INotifyDataErrorInfo
{
//定义异常属性
private ErrorsContainer<string> _errorsContainer;
public ErrorsContainer<string> ErrorsContainer
{
get
{
if (_errorsContainer == null)
{
_errorsContainer = new ErrorsContainer<string>(OnErrorHappend);
}
return _errorsContainer;
}
}
//当异常发生时,触发异常发生事件
private void OnErrorHappend(string obj)
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(obj));
}
public bool HasErrors => ErrorsContainer.HasErrors;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
return ErrorsContainer.GetErrors(propertyName);
}
}
继承BindableBase
类,定义属性并实现属性变化通知,在特定条件下发生异常
public class MainViewModel : BindableBase,INotifyDataErrorInfo
{
......//上文的内容
private int _value;
public int Value
{
get { return _value; }
set
{
if (value > 10)
{
ErrorsContainer.SetErrors("Value", new string[] { "数值不能大于10" });
}
SetProperty(ref _value, value);
}
}
}
异常消息展示
在xaml中进行异常消息的使用
<Window ......>
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<ControlTemplate TargetType="{x:Type TextBox}" x:Key="ct">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" SnapsToDevicePixels="True"
CornerRadius="5">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
VerticalContentAlignment="Center" Margin="3,5" BorderThickness="0"/>
</Border>
<TextBlock Grid.Row="1" Text="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource AncestorType=TextBox,Mode=FindAncestor}}"
Foreground="Red" Margin="10,5"
Name="txtError"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Visibility" Value="Visible" TargetName="txtError"/>
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<TextBlock Text="{Binding Value}"/>
<TextBox Text="{Binding Value,UpdateSourceTrigger=PropertyChanged}" Template="{StaticResource ct}"/>
</StackPanel>
</Grid>
</Window>