Prism 8在WPF项目中的使用

Prism 8在WPF项目中的使用

Prism可用来开发一个松耦合,可维护,可测试的WPF或者Xamain Forms,主要功能包括Delegate Commands,Composite Commands,Event Aggregation,Modules, Regions, Dependency Injection, Navigation, ViewModelLocator, Dialog Services。目前支持WPF,Xamain Forms,UNO。
接下来会介绍每个功能如何使用。

一、创建一个简单的Prism Demo

  1. 使用VS2017或以上创建一个WPF程序,添加Prism.Unity或者Prism.DryIoc,推荐使用前者。
    在这里插入图片描述
  2. 修改App.xaml:
<prism:PrismApplication x:Class="Centurion.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"
             xmlns:local="clr-namespace:Centurion">
    <!--StartupUri="Views/Shell.xaml"-->
    <Application.Resources>
         
    </Application.Resources>
</prism:PrismApplication>
 public partial class App : PrismApplication
    {
        
    }
  1. RegisterTypes:注册依赖。
    例如,现在有一个写log的接口,需要定义它的实现:
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            // Dependency Injection
            containerRegistry.RegisterSingleton<ILogger, Log>();
        }
  1. CreateShell:将创建应用程序的主窗口。
      protected override Window CreateShell()
        {
            return Container.Resolve<Shell>();
        }
  1. View Models:Prism有一个处理INotifyPropertyChanged基础设施的基类,该基础设施将从视图模型发布到视图的更改。还有一些其他的类可以使从视图模型中处理按钮变得简单,而不是在后台代码中编写事件处理程序。例如,Shell前台有一个"LogOn"按钮:
 <Grid HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid x:Name="MenuGrid" Grid.Row="0">
            <Button Content="LogOn" Width="100" Command="{Binding LogOnCommand}"/>
        </Grid>
    </Grid>

然后ShellViewModel定义LogOnCommand:

  public class ShellViewModel: BindableBase
    {
        public string _Title = "Prism Demo";
        public string Title
        {
            get { return _Title; }
            set { SetProperty(ref _Title, value); }
        }
        public DelegateCommand LogOnCommand { get; private set; }
        private IDialogService DialogService;
        public ShellViewModel(IDialogService _dialogService)
        {
            DialogService = _dialogService;
            LogOnCommand = new DelegateCommand(ShowLogOnDialog);
        }
        private void ShowLogOnDialog()
        {
            DialogService.ShowDialog("LogOnDialog", new DialogParameters($"message=123"), r =>
            {
                
            });
        }
    }
  1. 然后我们需要将上面的Shell和ShellViewModel绑定起来,就要用到ViewModelLocator:
<Window ...
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
      ...
      >

二、Prism功能介绍及代码示例

  1. Delegate Commands:这个功能简单理解就是在ViewModel中执行Command,像上面提到的,Shell有一个按钮LogOn需要绑定Command来实现LogOn功能,在ShellViewModel中定义LogOnCommand来实现。
<Window x:Class="Demo.Views.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        xmlns:local="clr-namespace:Centurion.Views"
        mc:Ignorable="d"
        Title="{Binding Title}" Height="450" Width="800">
    <Grid HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid x:Name="MenuGrid" Grid.Row="0">
            <Button Content="LogOn" Width="100" Command="{Binding LogOnCommand}"/>
        </Grid>
    </Grid>
</Window>
  public class ShellViewModel: BindableBase
    {
        public string _Title = "Prism Demo";
        public string Title
        {
            get { return _Title; }
            set { SetProperty(ref _Title, value); }
        }
        public DelegateCommand LogOnCommand { get; private set; }
        private IDialogService DialogService;
        public ShellViewModel(IDialogService _dialogService)
        {
            DialogService = _dialogService;
            LogOnCommand = new DelegateCommand(ShowLogOnDialog);
        }
        private void ShowLogOnDialog()
        {
            DialogService.ShowDialog("LogOnDialog", new DialogParameters($"message=123"), r =>
            {
                
            });
        }
    }
  1. Composite Commands:组合的Command,比如现在有按钮“Show All”, “Show Grid1”,“Show Grid2”,点击后,点击“Show All”按钮时,“Show Grid1”和“Show Grid2”的点击事件也要执行,那么就可以给“Show All”定义一个CompositeCommand ShowAllDelegateCommand,然后“Show Grid1”和“Show Grid2”的Command也要绑定到ShowAllDelegateCommand上。
public DelegateCommand ShowGrid1Command { get; private set; }
public DelegateCommand ShowGrid2Command { get; private set; }
public CompositeCommand ShowAllDelegateCommand { get; private set; }

public ViewAViewModel()
{
	ShowAllDelegateCommand = new CompositeCommand();
	ShowAllDelegateCommand.RegisterCommand(ShowGrid1Command);  
	ShowAllDelegateCommand.RegisterCommand(ShowGrid2Command); 
}
  1. Event Aggregation,事件聚合器,比如说我们需要收集整个程序所有模块的按钮动作,先定义一个MessageSentEvent:
    public class MessageSentEvent : PubSubEvent<string>
    {
    }

在需要使用的ViewModel中定义EventAggregator,使用事件发布:

 IEventAggregator EventAggregator;
  public ViewAViewModel(IEventAggregator ea)
  {
  	EventAggregator = ea;
  }

  private void Execute(string str)
 {
	EventAggregator.GetEvent<MessageSentEvent>().Publish("Publish ViewA Events.");
 }
 IEventAggregator EventAggregator;
  public ViewBViewModel(IEventAggregator ea)
  {
  	EventAggregator = ea;
  }

  private void Execute(string str)
 {
	EventAggregator.GetEvent<MessageSentEvent>().Publish("Publish ViewB Events.");
 }

在需要订阅的ViewModel中使用,这样每当其他ViewModel有事件发生,这里订阅的也会发生。

 private IEventAggregator EventAggregator;
 public ShellViewModel(IEventAggregator ea)
 {
    EventAggregator = ea;
    EventAggregator.GetEvent<MessageSentEvent>().Subscribe(MessageCollectAction, ThreadOption.UIThread);
 }
private void MessageCollectAction(string str)
{
   Logger.Log(str);      
}
  1. Modules,一个解决方案有多个模块,注册后才能使用这些模块的功能。
    定义模块LogModule:
  public class LogModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            var regionManager = containerProvider.Resolve<IRegionManager>();
            regionManager.RegisterViewWithRegion("LogContentRegion", typeof(LogView));
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {

        }
    }

在App.xaml.cs注册模块:

protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {   
             moduleCatalog.AddModule<LogModule.LogModule>();
        }
  1. Regions,区域管理,比如现在界面有一块区域Region,点Button A时显示A,点Button B时显示B,
    在这里插入图片描述
<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <StackPanel>
            <Button
                Margin="5"
                Command="{Binding OpenCommand}"
                CommandParameter="ViewA"
                Content="模块A" />
            <Button
                Margin="5"
                Command="{Binding OpenCommand}"
                CommandParameter="ViewB"
                Content="模块B" />
        </StackPanel>

        <ContentControl Grid.Column="1" prism:RegionManager.RegionName="ModuleContent" />
    </Grid>
<UserControl
    x:Class="BlankCoreApp1.Views.ViewA"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:BlankCoreApp1.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">
    <Grid Background="Red">
        <TextBlock
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontSize="60"
            Foreground="White"
            Text="我是模块A" />
    </Grid>
</UserControl>
public ShellViewModel(IRegionManager regionManager)
{
     _regionManage = regionManager;
     OpenCommand = new DelegateCommand<string>(OpenMethod);
}
private void OpenMethod(string obj)
{
    _regionManage.Regions["ModuleContent"].RequestNavigate(obj);
}

还需要在App.xaml.cs中注册这些区域视图:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
   containerRegistry.RegisterForNavigation<ViewA>();
   containerRegistry.RegisterForNavigation<ViewB>();
}
  1. Dependency Injection:将接口与继承相对应,譬如上面提到的写log的ILog接口,有两种实现,log到Txt文档和Log到一个客户的Webapi服务器。
private int Type { get; set; }
protected override void RegisterTypes(IContainerRegistry containerRegistry)
 {
     // Dependency Injection
    if (Type == 0)
    containerRegistry.RegisterSingleton<ILogger, LogToTxt>();
     else if (Type == 1)
        containerRegistry.RegisterSingleton<ILogger, LogToWebAPI>();
 }
  1. Navigation导航:
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<ViewB,ViewBViewModel>();
        }

实现导航页面的功能:

  public class ViewBViewModel : INavigationAware
    {
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            throw new NotImplementedException();
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            throw new NotImplementedException();
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            throw new NotImplementedException();
        }
    }
  1. ViewModelLocator:将View与ViewModel绑定起来。
  2. Dialog Services:将页面注册成对话框类型。
<UserControl x:Class="AccessControl.Views.NotificationDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:AccessControl.Views"
             mc:Ignorable="d" 
                   Width="300" Height="150">
    <Grid x:Name="LayoutRoot" Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <TextBlock Text="{Binding Message}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" TextWrapping="Wrap" />
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0" Grid.Row="1" >
            <Button Command="{Binding CloseDialogCommand}" CommandParameter="true" Content="OK" Width="75" Height="25" IsDefault="True" />
            <Button Command="{Binding CloseDialogCommand}" CommandParameter="false" Content="Cancel" Width="75" Height="25" Margin="10,0,0,0" IsCancel="True" />
        </StackPanel>
    </Grid>
</UserControl>
 public class NotificationDialogViewModel : BindableBase, IDialogAware
    {
        private string _message;
        public string Message
        {
            get { return _message; }
            set { SetProperty(ref _message, value); }
        }
        private string _title = "Notification";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }
        private DelegateCommand<string> _closeDialogCommand;
        public DelegateCommand<string> CloseDialogCommand =>
            _closeDialogCommand ?? (_closeDialogCommand = new DelegateCommand<string>(CloseDialog));
        public event Action<IDialogResult> RequestClose;
        protected virtual void CloseDialog(string parameter)
        {
            ButtonResult result = ButtonResult.None;

            if (parameter?.ToLower() == "true")
                result = ButtonResult.OK;
            else if (parameter?.ToLower() == "false")
                result = ButtonResult.Cancel;

            RaiseRequestClose(new DialogResult(result));
        }

        public virtual void RaiseRequestClose(IDialogResult dialogResult)
        {
            RequestClose?.Invoke(dialogResult);
        }
        public bool CanCloseDialog()
        {
            return true;
        }

        public void OnDialogClosed()
        {

        }

        public void OnDialogOpened(IDialogParameters parameters)
        {
            Message = parameters.GetValue<string>("message");
        }
    }
     public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterDialog<NotificationDialog, NotificationDialogViewModel>();// Dialog Service
        }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值