使用PopupRegion的WPF Prism应用程序在关闭时抛出无效窗口句柄

时间:2013-02-14 18:57:16

标签: wpf prism

我正在使用prism框架[.net 4.0]开发一个wpf应用程序。我使用StockTrader RI中的RegionPopupBehavior实现了一个弹出窗口。现在,当我使用窗口标题栏[主窗口]右上角的关闭按钮或使用

关闭主窗口时
Application.Current.Shutdown() 

单击按钮调用,我收到一条带有消息"无效窗口句柄"的win32异常。并且堆栈跟踪是所有互操作调用回到应用程序Run()调用。

我搜索谷歌和SO的答案无济于事。我在关闭期间设置了中断并检查了Windows集合,但它只显示主窗口为活动[如果弹出窗口被隐藏]。请注意,当我点击时,我收到弹出窗口是否打开的错误。

这是堆栈跟踪:

at MS.Win32.HwndWrapper.DestroyWindow(Object args)
   at MS.Win32.HwndWrapper.Dispose(Boolean disposing, Boolean isHwndBeingDestroyed)
   at MS.Win32.HwndWrapper.Dispose()
   at System.Windows.Interop.HwndSource.Dispose(Boolean disposing)
   at System.Windows.Interop.HwndSource.WeakEventDispatcherShutdown.OnShutdownFinished(Object sender, EventArgs e)
   at System.EventHandler.Invoke(Object sender, EventArgs e)
   at System.Windows.Threading.Dispatcher.ShutdownImplInSecurityContext(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.Dispatcher.ShutdownImpl()
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
   at RNDGroup.App.App.Main() in c:\Users\jgilliland\Projects\Common\Source\Prism GUI\RNDGroup.App\obj\x86\Release\App.g.cs:line 0
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

我的问题是,如果有人在类似的情况下看过它,我该如何解决这个问题,或者如何进一步调试这个win32例外?谢谢,j

1 个答案:

答案 0 :(得分:1)

我的团队的技术负责人发现了问题并删除了此错误。弹出区域用于在其自己的窗口中显示/隐藏或者激活/取消激活VirtualKeyboardView。当我在用户点击按钮时从显示键盘切换到每当文本框获得焦点时显示键盘时,就会出现“无效窗口句柄”win32异常。

焦点事件有点滑稽,我看到了用户对同一点击/焦点的多个焦点事件。无论如何,故事的结尾是我意识到问题是重复的焦点事件,但我找不到问题的根源。我的队友能够追踪这些看似重复的文本框焦点事件引起的递归问题。解决方案是跟踪导致键盘显示的最后一个文本框元素,并基本上忽略重复的焦点事件。这删除了无效窗口句柄的win32异常。

我知道这是一个奇怪的问题,甚至更奇怪的答案,但这是我第一次在这样的论坛中发布一个问题,我显然需要学习如何更好地提出问题。但是,由于我非常有帮助的团队领导,我能够摆脱错误,继续在辅助弹出区域中的wpf中实现这个虚拟键盘。它一直是一种学习经历。

以下是一些可能有助于澄清答案的代码。这来自管理显示和隐藏键盘视图的VirtualKeyboardService。

/// <summary>
/// Opens the keyboard.
/// </summary>
public void OpenKeyboard()
{
    lock (_lock)
    {
        // allow for ignoring a refocus one time
        if (_ignoreOnce)
        {
            _ignoreOnce = false;
            return;
        }
        // open keyboard if not already open
        if (!_isKeyboardOpen)
        {
            var viewName = typeof(VirtualKeyboardView).FullName;
            _regionManager.RequestNavigate(RegionNames.PopupRegion, new Uri(viewName, UriKind.Relative));
            _isKeyboardOpen = true;
            _lastImpression = null;
        }
    }
}

这是关闭虚拟键盘的方法,当用户单击关闭按钮时,或者当它们点击enter,tab或esc键时,从键盘的视图模型调用此方法。它也是从MainWindow的Activated事件的事件处理程序调用的     ///     ///关闭键盘     ///     ///如果设置为true [恢复文本]。     public void CloseKeyboard(bool revertText = false)     {         锁(_lock)         {             //关闭键盘视图             var view = _regionManager.Regions [RegionNames.PopupRegion] .ActiveViews.FirstOrDefault();

        if (view != null)
        {
            _regionManager.Regions[RegionNames.PopupRegion].Deactivate(view);
            _isKeyboardOpen = false;
            _lastImpression = CurrentTarget;
        }

        // revert text if needed
        if (revertText && CurrentTarget != null)
        {
            CurrentTarget.Text = CurrentText;
        }
    }
}

这也很棘手,这就是忽略曾经发挥作用的地方。当用户点击“离开”激活主窗口时,我必须能够关闭键盘视图,主窗口可能集中在文本框上,导致键盘视图重新出现。忽略一次选项允许突破该循环。自动显示虚拟键盘涉及许多不同的用例。我在wpf ...

中学到了很多关于使用行为和复合命令的知识