Prism進入檢視時導航的三種方式

2023-06-22 06:00:39

Prism導航

  1. 新建檢視UserControl及其ViewModel,被跳轉的檢視的VM需要實現INavigationAware

  2. App.xaml.cs中註冊檢視及其ViewModel

// App.xaml.cs
containerRegistry.RegisterForNavigation<IndexView, IndexViewModel>();
  1. 在需要放置導航內容處宣告ContentControlregion佔位:
    <DockPanel LastChildFill="True">
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="5" >
            <Button Command="{Binding NavigateCommand}" CommandParameter="ViewA" Margin="5">Navigate to View A</Button>
            <Button Command="{Binding NavigateCommand}" CommandParameter="ViewB" Margin="5">Navigate to View B</Button>
        </StackPanel>
        <ContentControl prism:RegionManager.RegionName
            ="{x:Static ext:PrismManager.MainViewRegionName}" />
    </DockPanel>
  • RegionPrism內部的一個資料結構,它的Name屬性是此處在XAML中宣告的RegionName(詳見下節)。
  1. 在需要進行導航行為的ViewModel處注入並使用,如:
// ViewModel
        public DelegateCommand<string> NavigateCommand { get; private set; }

        public MainWindowViewModel(IRegionManager regionManager)
        {
            _regionManager = regionManager;

            NavigateCommand = new DelegateCommand<string>(Navigate);
        }

        private void Navigate(string navigatePath)
        {
            if (navigatePath != null)
                _regionManager.RequestNavigate("ContentRegion", navigatePath);
        }

RegionManager

  • Region 對應的是在XAML中宣告的 ContentControl 的附加屬性 prism:RegionManager.RegionName

  • RegionManager 管理著所有 Region 物件,這些 Region 物件被裝到 RegionCollection 中的列表屬性

  • RegionManager中的3個方法

    • UpdateRegionsPrismApplicationBase#Initialize 中被呼叫,它會根據在XAML中宣告的RegionName 建立 Region 物件
    • RequestNavigate 在需要導航時呼叫,呼叫它時會根據 regionName 去 regionCollection 中找到對應的 Region 物件,並通過集合 ActiveViews 找到滿足條件的 View 範例從而進行 ContentControl內容的切換
    • 可以主動呼叫 RegisterViewWithRegion 進行 Region 和檢視的註冊

在進入檢視時導航

由於 View 和 ViewModel 的初始化 MvvmHelpers.AutowireViewModel(shell); 先於 Region 的初始化RegionManager.UpdateRegions();,因此在View和ViewModel初始化時找不到相應的 Region 物件。

// PrismApplicationBase.cs
protected virtual void Initialize()
{
    // ...
    if (shell != null)
    {
        MvvmHelpers.AutowireViewModel(shell);
        RegionManager.SetRegionManager(shell, _containerExtension.Resolve<IRegionManager>());
        RegionManager.UpdateRegions();
        InitializeShell(shell);
    }
    // ...

在視窗初始化時,Initilized 事件發生時資料繫結未完成;Loaded 事件發生時資料繫結已經完成。

因此,可以手動註冊 Region;也可以在資料繫結結束之後存取 Region

方法1 Loaded事件

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    regionManager.RequestNavigate("ContentRegion", "ViewA");
}

方法2 手動註冊 Region

// App.xaml.cs
protected override void Initialize()
{
    base.Initialize();

    var regionManager = Container.Resolve<IRegionManager>();
    regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));
}

// ViewModel
public MainWindowViewModel(IRegionManager regionManager)
{
    regionManager.RequestNavigate("ContentRegion", "ViewA");
}

方法3 Dispatcher

Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
    regionManager.RequestNavigate("ContentRegion", "ViewA");
}));

參照

  1. Prism - Region navigation
  2. learn.microsoft - Object lifetime events (WPF .NET)