简介

Prism是一个用于WPF、Xamarin Forms、WinUI等的MVVM框架,刚刚学习,这里只是个人总结的一些知识点笔记。

IoC

IContainerProvider

1
2
3
4
protected override Window CreateShell()
{
    return Container.Resolve<MainWindow>();
}
1
2
3
4
5
6
public void OnInitialized(IContainerProvider containerProvider)
{
    var regionManager = containerProvider.Resolve<IRegionManager>();
    var viewA = containerProvider.Resolve<ViewA>();
    ...
}

IContainerRegistry

1
2
3
4
5
6
7
8
9
// App.xaml.cs
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.Register<IApplicationCommands, ApplicationCommands>();
    containerRegistry.RegisterDialog<NotificationDialog, NotificationDialogViewModel>();
    containerRegistry.RegisterForNavigation<Page1>();
    containerRegistry.RegisterForNavigation<Page2>();
    ...
}

Module

IModule

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class SimpleModule : IModule
{
    public void OnInitialized(IContainerProvider containerProvider)
    {
    }

    public void RegisterTypes(IContainerRegistry containerRegistry)
    {
    }
}

使用App.config加载模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<!-- App.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf" />
  </configSections>
  <startup>
  </startup>
  <modules>
    <module assemblyFile="Simple.dll" moduleType="Simple.SimpleModule, Simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="SimpleModule" startupLoaded="True" />
  </modules>
</configuration>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// App.xaml.cs
public partial class App : PrismApplication
{
    ...

    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new ConfigurationModuleCatalog();
    }

    ...
}

直接引用加载模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// App.xaml.cs
public partial class App : PrismApplication
{
    ...

    protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
    {
        moduleCatalog.AddModule<SimpleModule>();
    }

    ...
}

指定模块文件夹

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// App.xaml.cs
public partial class App : PrismApplication
{
    ...

    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
    }

    ...
}

使用ModuleCatalog加载模块

1
2
3
4
5
6
7
8
<m:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:m="clr-namespace:Prism.Modularity;assembly=Prism.Wpf">

    <m:ModuleInfo ModuleName="Simple"
                  ModuleType="Simple.SimpleModule, Simple, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

</m:ModuleCatalog>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// App.xaml.cs
public partial class App : PrismApplication
{
    ...

    protected override IModuleCatalog CreateModuleCatalog()
    {
        return ModuleCatalog.CreateFromXaml(new Uri("/Modules;component/ModuleCatalog.xaml", UriKind.Relative));
    }

    ...
}

Command

DelegateCommand

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public DelegateCommand ExecuteDelegateCommand { get; }
public DelegateCommand<string> ExecuteGenericDelegateCommand { get; }
public DelegateCommand DelegateCommandObservesProperty { get; }
public DelegateCommand DelegateCommandObservesCanExecute { get; }

ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);

DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => IsEnabled);

DelegateCommandObservesCanExecute = new DelegateCommand(Execute).ObservesCanExecute(() => IsEnabled);

ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric).ObservesCanExecute(() => IsEnabled);

CompositeCommand

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public CompositeCommand SampleCommand { get; } = new CompositeCommand(true);

...

DelegateCommand UpdateCommand = new DelegateCommand(Update).ObservesCanExecute(() => CanUpdate);

SampleCommand.RegisterCommand(UpdateCommand);

...

private void OnIsActiveChanged()
{
    UpdateCommand.IsActive = IsActive;

    IsActiveChanged?.Invoke(this, new EventArgs());
}

Event To Command

1
2
3
4
5
6
<i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged">
        <prism:InvokeCommandAction Command="{Binding PersonSelectedCommand}"
            CommandParameter="{Binding ElementName=ListOfPerson, Path=SelectedItem}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

BindableBase

1
2
3
4
public class ViewAViewModel : BindableBase, IActiveAware
{
    ...
}

ViewModelLocator

AutoWireViewModel

1
2
3
4
<Window x:Class="Demo.Views.MainWindow"
    ...
    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True">

更改命名约定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// App.xaml.cs
public partial class App : PrismApplication
{
    ...

    protected override void ConfigureViewModelLocator()
    {
        base.ConfigureViewModelLocator();
        ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
        {
            var viewName = viewType.FullName.Replace(".ViewModels.", ".CustomNamespace.");
            var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
            var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}";
            return Type.GetType(viewModelName);
        });
    }

    ...
}

自定义ViewModel注册

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// App.xaml.cs
public partial class App : PrismApplication
{
    ...

    protected override void ConfigureViewModelLocator()
    {
        base.ConfigureViewModelLocator();

        // type / type
        ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(CustomViewModel));

        // type / factory
        ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve<CustomViewModel>());

        // generic factory
        ViewModelLocationProvider.Register<MainWindow>(() => Container.Resolve<CustomViewModel>());

        // generic type
        ViewModelLocationProvider.Register<MainWindow, CustomViewModel>();
    }

    ...
}

EventAggregator

IEventAggragator

1
2
3
4
public interface IEventAggregator
{
    TEventType GetEvent<TEventType>() where TEventType : EventBase;
}

创建消息事件类

1
2
3
public class SimpleMessageEvent : PubSubEvent<string>
{
}

订阅事件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
private readonly IEventAggregator eventAggregator;

public MainPageViewModel(IEventAggregator ea)
{
    eventAggregator = ea;
    ea.GetEvent<SimpleMessageEvent>().Subscribe(ShowMessage);
    // Subscribing on the UI Thread
    // ea.GetEvent<SimpleMessageEvent>().Subscribe(ShowMessage, ThreadOption.UIThread);
}

public void ShowMessage(string payload)
{
    // TODO
}

发布消息

1
eventAggregator.GetEvent<SimpleMessageEvent>().Publish("Hello!");

筛选订阅

1
ea.GetEvent<SimpleMessageEvent>().Subscribe(ShowMessage, ThreadOption.UIThread, keepSubscriberReferenceAlive, x => x.Contains(" "));

取消订阅

1
eventAggregator.GetEvent<SimpleMessageEvent>().Unsubscribe(ShowMessage);

RegionManager

1
2
3
4
5
6
7
8
9
<Window x:Class="Regions.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        Title="Shell">
    <Grid>
        <ContentControl prism:RegionManager.RegionName="ContentRegion" />
    </Grid>
</Window>
1
2
3
// IContainerProvider containerProvider
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));
1
2
3
4
5
6
7
// IContainerProvider containerProvider
var regionManager = containerProvider.Resolve<IRegionManager>();
var region = regionManager.Regions["ContentRegion"];

region.Add(containerProvider.Resolve<ViewA>());
region.Add(containerProvider.Resolve<ViewB>());
region.Add(containerProvider.Resolve<ViewC>());

RegionNavigation

1
2
// IRegionManager regionManager
regionManager.RequestNavigate(regionName: "NavigateRegion", source: "Page1");

Navigation Callback

1
2
3
4
5
6
7
// IRegionManager regionManager
regionManager.RequestNavigate(regionName: "NavigateRegion", source: "Page1", navigationCallback: NavigationComplete);

private void NavigationComplete(NavigationResult result)
{
    dialogService.ShowDialog("NotificationDialog", new DialogParameters($"message=Navigate to {result.Context.Uri} complete."), null);
}

Navigation Parameters

1
2
3
4
5
6
var parameters = new NavigationParameters
{
    { "content", "Hello!" }
};
// IRegionManager regionManager
regionManager.RequestNavigate(regionName: "NavigateRegion", source: "Page1", navigationParameters: parameters);

INavigationAware

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Page1ViewModel : BindableBase, INavigationAware
{
    ...

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }

    public void OnNavigatedFrom(NavigationContext navigationContext)
    {
    }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        if (navigationContext.Parameters["content"] is string content)
        {
            // TODO
        }
    }

    ...
}

IConfirmNavigationRequest

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class Page1ViewModel : BindableBase, IConfirmNavigationRequest
{
    ...

    public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
    {
        bool result = true;
        ButtonResult buttonResult = ButtonResult.None;

        dialogService.ShowDialog("NotificationDialog",
            new DialogParameters($"message=Do you to navigate?"),
            res => { buttonResult = res.Result; });

        if (buttonResult != ButtonResult.OK)
            result = false;

        continuationCallback(result);
    }

    ...
}

IRegionMemberLifetime

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Page1ViewModel : BindableBase, INavigationAware, IRegionMemberLifetime
{
    public bool KeepAlive
    {
        get
        {
            return false;
        }
    }

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return false;
    }

    public void OnNavigatedFrom(NavigationContext navigationContext)
    {
    }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
    }
}

Navigation Journal

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class Page1ViewModel : BindableBase, INavigationAware
{
    private IRegionNavigationJournal journal;

    public DelegateCommand GoForwardCommand { get; }
    public DelegateCommand GoBackCommand { get; }

    public Page1ViewModel()
    {
        GoForwardCommand = new DelegateCommand(GoForward, CanGoForward);
        GoBackCommand = new DelegateCommand(GoBack);
    }

    ...

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }

    public void OnNavigatedFrom(NavigationContext navigationContext)
    {
    }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        journal = navigationContext.NavigationService.Journal;
        GoForwardCommand.RaiseCanExecuteChanged();
    }

    ...

    private bool CanGoForward()
    {
        return journal != null && journal.CanGoForward;
    }

    private void GoForward()
    {
        journal?.GoForward();
    }

    private void GoBack()
    {
        journal?.GoBack();
    }
}

DialogService

See DOC. Dialog Service

1
2
3
4
5
6
// DialogServiceModule.cs
public void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterDialog<NotificationDialog, NotificationDialogViewModel>();
    // containerRegistry.RegisterDialogWindow<MyRibbonWindow>();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// viewmodel
private readonly IDialogService dialogService;

public MainViewModel(IDialogService dialogService)
{
    this.dialogService = dialogService;
}

private void NavigationComplete(NavigationResult result)
{
    // Show Dialog with parameters.
    dialogService.ShowDialog("NotificationDialog", new DialogParameters($"message=Navigate to {result.Context.Uri} complete."), null);
}

参考