Prism 区域切换与容器实例同步

Prism Region Switching and Synchronizing with Container Instance

我正在 WPF 中使用具有 (Prism) 区域 "MainViewRegion" 的 MainWindow。这会根据用户所需的视图进行切换,当它切换时,主窗口会调整大小以捕捉到嵌入视图的新尺寸。

我有一些代码可以在区域切换后使 window 在桌面上完全可见。这是代码:

private void WindowModeChange(string uri)            
{

        IRegion mviewRegion = regionManager.Regions[RegionNames.MainViewRegion];

        if (mviewRegion == null) return;

        regionManager.RequestNavigate(mviewRegion.Name, new Uri(uri, UriKind.Relative));

            //Get the MainWindow instance from the container
            var uc = container.Resolve<MainWindow>(InstanceNames.MainWindowView);
            //Make sure the entire window is visible onscreen
            ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(uc);
}

问题是 "uc" 变量将始终等于区域更改之前的 MainWindow 参数。 "uc" 总是比我想要的落后一步,所以 "snap-to" 代码总是关闭。

我错过了什么?

感谢 Grx70 在我的问题的评论中,他给了我解决方案。该方法的主体现在显示为:

IRegion mviewRegion = regionManager.Regions[RegionNames.MainViewRegion];

        if (mviewRegion == null) return;


        mviewRegion.RequestNavigate(new Uri(uri, UriKind.Relative), (x =>
        {

            var uc = container.Resolve<MainWindow>(InstanceNames.MainWindowView);
            uc.Dispatcher.Invoke(() => ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(uc), DispatcherPriority.Loaded);

        }));

我不确定为什么我必须在 RequestNavigate() 的回调参数中调用 Dispatcher,但没有它就无法工作。

通常当你有一段代码在某个事件上执行时,你需要确保 UI 已经在某种程度上响应了那个事件,你最好的选择是使用 Dispatcher 推迟执行。根据您提供的代码判断,UI 更改是由 regionManager.RequestNavigate 调用触发的。现在我无法向您指出一段说明该内容的文档,但我从经验中知道框架将 异步处理此请求 ,即控制权将返回给您的方法(允许它继续)在此请求引起的所有工作完成之前(因此你的问题)。这是(据我所知)框架通过使用上述 Dispatcher.

在内部完成的

根据您需要框架在多大程度上处理触发的更改,您应该使用适当的 DispatcherPriority 枚举值来确保在执行代码后完成某些事情。根据您的问题,我认为 DispatcherPriority.Loaded 是一个不错的选择(根据文档,调度程序将在呈现 UI 之后执行此类代码(这对您来说是至关重要的条件),但在任何用户输入之前处理)。我个人倾向于将优先级最大化,直到它停止工作(可能避免由例如用户输入引起的一些意外行为)。

因此,对代码的这种修改应该足以实现您的目标:

var uc = container.Resolve<MainWindow>(InstanceNames.MainWindowView);
uc.Dispatcher.InvokeAsync(() =>
    ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(uc),
    DispatcherPriority.Loaded);

现在我注意到你最终选择了 Dispatcher.Invoke 而不是 Dispatcher.InvokeAsync - 我想你的情况没问题,因为它是你方法中的最后一条指令,但通常安全的方法是使用 Dispatcher.InvokeAsync(我亲身经历过 Dispatcher.Invoke 没有切芥末的情况)。