我在WPF中使用具有(Prism)区域“MainViewRegion”的MainWindow。这会根据用户所需的视图进行切换,当它发生时,MainWindow会调整大小以捕捉嵌入视图的新维度。
我有一些代码可以在Region切换后让桌面在桌面上完全可见。这是代码:
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”代码总是关闭。
我错过了什么?
答案 0 :(得分:1)
通常,如果您有一段代码在某个事件上执行,并且您需要确保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
未切割芥末的情况。)
答案 1 :(得分:0)
感谢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()的callback参数中调用Dispatcher,但没有它就无法工作。