【问题标题】:Dialogs with regions in a WPF Application using PRISM使用 PRISM 的 WPF 应用程序中的区域对话框
【发布时间】:2014-05-29 08:53:39
【问题描述】:

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

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

我现在的问题是,有时我需要打开第二个模式对话框,该对话框也需要可导航。如果我使用我的对话服务,我将获得对话窗口的新实例并引发异常,因为该区域已经向 regionmanager 注册(它在对话窗口后面的代码中完成)。这是有道理的,因为 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();
    }
}

【问题讨论】:

  • 我试图打开一个对话框(只有一层),你的代码看起来很鼓舞人心。但我无法理解 IModalDialog。你能显示那部分代码吗?如果您可以分享您的代码示例,那将是很大的帮助

标签: c# wpf mvvm dialog prism


【解决方案1】:

而不是用RegionManager 重新注册Region。您可以重用已注册的初始 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;
}

【讨论】:

  • 感谢您的想法。你有更多的信息吗? msdn 上的文档不是很详尽...我的问题是:如何在另一个视图中获取特定范围的 regionmanager?如何在服务中获得正确的 regionmanager(我需要它来启动导航)?我需要在对话框中注册区域,因为窗口接收到一个新的 regionmanager-instance,因为它没有通过搜索树找到 shell 的 regionmanager。
  • 我想我知道该怎么做,但你需要发布你的代码让我确定。
  • 我已经编辑了我的答案,虽然我可能是错的;除了确保每个对话框都有自己的区域管理器作用域外,我还必须考虑导航等问题(即调用 regionManager.RequestNavigate&lt;MyViewModel2&gt;(Regions.DialogRegion); 时会发生什么)以及如果您删除具有区域管理器作用域的视图会发生什么。
  • 谢谢乔治,但这不起作用。问题是,如果没有RegionManager.SetRegionManager(this, regionManager);,该区域未在区域管理器中注册,因此无法找到。如果我先添加它,我会得到一个InvalidOperationException。我更新了 m 帖子以显示我如何连接视图和模型,因为我认为对话框窗口不是视图,因此方法调用 ...Add(this,...) 是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
相关资源
最近更新 更多