WPF Prism 入门 1
1.新建prsim工程,修改工程
新建wpf工程,Nuget添加prism.Unity,自动添加需要的包
项目结构:
修改App.xaml
修改前:
修改后:
App.xaml.cs:
到这一步,一个wpf基于prism的工程就可以运行了,修改一下项目结构,用于自动绑定ViewModel
把MainWindow放到Views下,需要修改3个地方
Mainwindow.xaml:命名空间
x:Class="Demo.Views.MainWindow"
Mainwindow.xaml.cs命名空间
namespace Demo.Views
app.xaml.cs中命名空间(需要实现接口CreateShell()和RegisterTypes)
return Container.Resolve<Views.MainWindow>();
prism工程默认把界面放在Views目录下,把对应的View Model、
放在ViewModel目录下
2.View和ViewModel的绑定
prism会自动完成View和ViewModel的绑定,前提条件是:
1.View中引入名称空间:xmlns:prism="http://prismlibrary.com/"
2.设置为自动关联:prism:ViewModelLocator.AutoWireViewModel="True"
3.必须是Views和ViewModels目录,目录的名字不能变
4.需要保证命名规范的正确性
- View可以以View结尾,也可以不写。
- ViewModel必须以View的名称+”ViewModel”进行命名
这些是默认的规则,也可以通过App.cs 中重写ConfigureViewModelLocator方法自定义规则
代码:在App.xaml.cs中
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(TestVM));
}
在默认规则下,Views下的MianWindow会自动绑定MainWindowViewModel,通过修改规则,让他绑定到TestVM上
两个类的代码:
运行结果:
3.属性的绑定和通知
在Prism框架下要完成属性的绑定和自动通知,只需要做2步即可
1.在属性所在的类继承BindableBase基类
2.在属性的set访问器中添加SetProperty(ref xxx, value)
public class MainWindowViewModel : BindableBase
{
private string str;
public string Str
{
get { return str; }
set { SetProperty(ref str, value); }
}
public MainWindowViewModel()
{
Str = "Binding";
}
}
}
在SetProperty中加了数据的判断,只有数据真正有变化时才会执行RaisePropertyCHanged,如果数据和之前的数据相同,则不执行。这样做提高了程序的效率
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value))
{
return false;
}
storage = value;
RaisePropertyChanged(propertyName);
return true;
}
4.命令的绑定
使用快捷键输入,输入按2此Tab。总共有4个
cmd 不带参数和CanEexecute方法的命令
private DelegateCommand _fieldName; public DelegateCommand CommandName => _fieldName ?? (_fieldName = new DelegateCommand(ExecuteCommandName)); void ExecuteCommandName() { }
cmdgfull 带参数和CanExecute方法的命令
private DelegateCommand<string> _fieldName; public DelegateCommand<string> CommandName => _fieldName ?? (_fieldName = new DelegateCommand<string>(ExecuteCommandName, CanExecuteCommandName)); void ExecuteCommandName(string parameter) { } bool CanExecuteCommandName(string parameter) { return true; }
cmdfull 不带参数,带Canexecute方法的命令
private DelegateCommand _fieldName; public DelegateCommand CommandName => _fieldName ?? (_fieldName = new DelegateCommand(ExecuteCommandName, CanExecuteCommandName)); void ExecuteCommandName() { } bool CanExecuteCommandName() { return true; }
cmdg 带参数不带Canexecute方法的命令
private DelegateCommand<string> _fieldName; public DelegateCommand<string> CommandName => _fieldName ?? (_fieldName = new DelegateCommand<string>(ExecuteCommandName)); void ExecuteCommandName(string parameter) { }
命令都是固定格式的,只需要修改命令的名字,参数的类型,传入委托即可。
一个命令的固定格式分析,在写自己的命令时,自己决定是不是要传参数,要不要CanExecute方法
运行结果:
点击按钮前:
点击按钮后:
5.InvokeCommandAction任意事件的绑定
和mvvmlight,mvvmtoolkit一样,只有少数控件有Command参数,下面接受在Prism框架下,任意事件的绑定(为什么绑定命令?可以简单理解,实现界面和数据分离,可以在ViewModel中写命令的处理逻辑)
第一步:在View中添加命名空间
xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:prism="http://prismlibrary.com/"
第二步:给Combox的SelectionChanged添加命令
<ComboBox> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <prism:InvokeCommandAction Command="{Binding ComboxSelectedChanged}" /> </i:EventTrigger> </i:Interaction.Triggers> <ComboBoxItem Content="111"/> <ComboBoxItem Content="222"/> <ComboBoxItem Content="333"/> </ComboBox>
ViewModel中:
private DelegateCommand<object> comboxSelectedChanged; public DelegateCommand<object> ComboxSelectedChanged => comboxSelectedChanged ?? (comboxSelectedChanged = new DelegateCommand<object>(ExecuteComboxSelectedChanged)); void ExecuteComboxSelectedChanged(object parameter) { }
需要注意的时命令的参数要写Object类型,按照这个步骤,可以给任意的控件的任意事件绑定到命令,默认是传递EventArgs
6.事件聚合器,订阅 发布
Prism框架下,View和ViewModel之间互相传递消息
1.定义一个基本消息类型MessageEvent,继承PubSubEvent
这个MessageEvenet继承PubSubEvent,<>括号内写消息的类型,
例子1:View和ViewModel之间传递消息
View:
public partial class MainWindow : Window
{
public MainWindow( IEventAggregator eventAggregator)
{
InitializeComponent();
eventAggregator.GetEvent<MessageEvent>().Subscribe(On);
}
private void On(object obj)
{
}
}
ViewModel:
构造函数注入TEventAggregator
public IEventAggregator MyEventAggregator; public MainWindowViewModel( IEventAggregator eventAggregator) { // Str = "Binding"; MyEventAggregator = eventAggregator; }
当什么时候,发送这个消息,(当Combox发生SelectionCHanged事件后发送消息,这是我随便找的,具体在哪里发送,看自己的需求)
private DelegateCommand<object> comboxSelectedChanged; public DelegateCommand<object> ComboxSelectedChanged => comboxSelectedChanged ?? (comboxSelectedChanged = new DelegateCommand<object>(ExecuteComboxSelectedChanged)); void ExecuteComboxSelectedChanged(object parameter) { MyEventAggregator.GetEvent<MessageEvent>().Publish(parameter); }
需要注意的几点:
1.Prism框架下,在同一程序中获取 IEventAggregator ,都是同一个对象,这个是由IOC容器提供的功能,
2.发布消息 和订阅消息的双发需要根据消息的类型判断是否匹配
3.在需要的使用IEventAggregator的View或者ViewModel中,在该类的构造函数中注入IEventAggregator
4.View ViewModel之间可以互相定于和发布。 即使不在同一个程序集也可以。(使用Prism的Module的情况下,需要把消息类型写在公共程序集中)
至此,Prism的基本功能包括 新建工程,初始化app,属性的绑定和通知,命令的绑定,消息的传递就介绍完了。