使用PRISM在WPF应用程序中与区域对话

时间:2014-04-15 06:43:08

标签: c# wpf mvvm dialog prism

我正在使用PRISM / Unity和MVVM方法开发WPF应用程序。到目前为止一切都很好,但我认为我有一个概念问题。

由于我需要模态对话框,我实现了一个对话服务,它被注入到视图模型中,可以用来打开一个带有相应视图的模态对话框。此对话框需要可导航(=包含区域),以便我能够在对话框中切换视图。为此,服务创建窗口的实例并导航到DialogRegion中的请求视图。这也有效。

我现在的问题是,在某些时候我需要打开第二个模态对话框,该对话框也需要可导航。如果我使用我的对话服务,我会得到一个对话窗口的新实例,并抛出一个异常,因为该区域已经注册了regionmanager(它在对话框窗口后面的代码中完成)。这是有道理的,因为区域管理者不能区分区域,但是阻止我打开第二个可导航的对话框。

什么是更好的方法?我只能想到为该地区创建一个具有不同名称的第二个对话框窗口,但这似乎是一个非常难看的解决方案......


编辑1: 显示对话框的代码:

dialogService.ShowDialog<MyViewModel>();

对话框服务中用于显示对话框的代码:

public void ShowDialog<TDialogViewModel>() where TDialogViewModel : class
{
    IModalDialog dialog = ServiceLocator.Current.TryResolve<IModalDialog>();
    dialog.Owner = Application.Current.MainWindow;
    regionManager.RequestNavigate(typeof(TDialogViewModel), Regions.DialogRegion);
    dialog.ShowDialog();
}

对话窗口中的代码:

public DialogWindow(IRegionManager regionManager) : this()
{
    RegionManager.SetRegionManager(this, regionManager);
    this.regionManager = regionManager;
}
private void Window_Unloaded(object sender, RoutedEventArgs e)
{
    regionManager.Regions.Remove(Regions.DialogRegion);
    regionManager.Regions.Remove(Regions.DialogStatusRegion);
}

构建,导航和显示其他对话框视图中的代码

public MyViewModel(IRegionManager regionManager, IModalDialogService dialogService) : this()
{
    this.regionManager = regionManager;
    this.dialogService = dialogService;
}
void NavigateToSecondView()
{
    regionManager.RequestNavigate<MyViewModel2>(Regions.DialogRegion);
}
void ShowDialog2()
{
    // This is where a second dialog window with MyViewModel3 should be shown
    dialogService.ShowDialog<MyViewModel3>();
}

编辑2: 窗口的XAML:

<Window.Resources>
    <DataTemplate DataType="{x:Type localModels:MyViewModel}">
        <localViewsProject:MyView/>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ContentControl Grid.Row="0" x:Name="DialogContent" Margin="10,10,10,10" 
                    prismRegions:RegionManager.RegionName="{x:Static navi:Regions.DialogRegion}">
    </ContentControl>
</Grid>

编辑3 - IModalDialog的代码: 我在网络的某个地方得到了IModalDialog的想法,但我不记得在哪里。我们的想法是拥有一个由一些窗口实例实现的接口,并允许与用户进行交互。我的对话框只有一个内容区域(加上状态/进度通知区域),可以通过棱镜填充。

这里有一些代码来解释这个想法:

public partial class DialogWindow : Window, IModalDialog
{
    internal IRegionManager regionManager;

    public DialogWindow()
    {
        InitializeComponent();
    }

    public DialogWindow(IRegionManager regionManager)
        : this()
    {
        RegionManager.SetRegionManager(this, regionManager);
        this.regionManager = regionManager;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        // Load Model, when window is loaded
        BaseViewModel model = this.DialogContent.Content as BaseViewModel;
        if (model != null)
        {
            model.LoadData();
        }
    }

    private void Window_Unloaded(object sender, RoutedEventArgs e)
    {
        regionManager.Regions.Remove(Regions.DialogRegion);
        regionManager.Regions.Remove(Regions.DialogStatusRegion);
    }
}

因此,为了使用它,我有一个静态ModalDialogService,它接收一个模型,并在关闭对话框后完成一些操作。像这样:

public void ShowDialog<TDialogViewModel>(Action<TDialogViewModel> initializeAction = null, Action<TDialogViewModel> actionAfterClose = null) where TDialogViewModel : class
{
    IModalDialog dialog = ServiceLocator.Current.TryResolve<IModalDialog>();
    if (actionAfterClose != null)
    {
        WeakEventManager<IModalDialog, EventArgs>.AddHandler(
                dialog,
                "Closed",
                (sender, e) => dialogView_Closed(sender, e, typeof(TDialogViewModel), Regions.DialogRegion, actionAfterClose));
        }

        dialog.Owner = Application.Current.MainWindow;
        regionManager.RequestNavigate(typeof(TDialogViewModel), Regions.DialogRegion);

        TDialogViewModel model = null;
        var region = regionManager.Regions[Regions.DialogRegion];

        foreach (var view in region.ActiveViews)
        {
            if (view is TDialogViewModel)
            {
                model = (TDialogViewModel)view;
                if (initializeAction != null)
                {
                    initializeAction(model);
                }
            }
        }

        // Attach an event listener to the closing event in order to prevent closing
        // if the form is not in a closeable state.
        if (typeof(IConfirmNavigationRequest).IsAssignableFrom(typeof(TDialogViewModel)))
        {
            WeakEventManager<IModalDialog, CancelEventArgs>.AddHandler(
                dialog,
                "Closing",
                (sender, e) => dialogView_Closing(sender, e, Regions.DialogRegion));
        }

        // This event can be published by a viewmodel in order to close the dialog
        eventAggregator.GetEvent<DialogCloseRequestedEvent>().Subscribe((containingDialog) =>
        {
            if (containingDialog == model)
            {
                dialog.Close();
            }
        });

        dialog.ShowDialog();
    }
}

1 个答案:

答案 0 :(得分:0)

而不是使用Region重新注册RegionManager。您可以重用已注册的初始Region并创建它的多个实例。这些被称为Scoped Regions(在创建区域的多个实例部分下)。例如:

// You may need to keep track of these scopes
IRegionManager scopedRegionManager = _regionManager.Regions["DialogRegion"].Add(view, viewName, true);
scopedRegionManager.Navigate(viewName);

修改

我相信这就像将DialogWindow的构造函数更改为:

一样简单
public DialogWindow(IRegionManager regionManager) : this()
{
    var scopedRegionManager = regionManager.Regions[Regions.DialogRegion].Add(this, null, true);
    this.regionManager = scopedRegionManager;
}