【问题标题】:WPF Prism application using PopupRegion throws Invalid Window Handle on close使用 PopupRegion 的 WPF Prism 应用程序在关闭时抛出 Invalid Window Handle
【发布时间】:2013-02-14 18:57:16
【问题描述】:

我正在使用 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

【问题讨论】:

    标签: wpf prism


    【解决方案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;
            }
        }
    }
    

    这是关闭虚拟键盘的方法,当用户单击关闭按钮,或者当他们按下回车键、制表符或 esc 键时,它会从键盘的视图模型中调用。它也从 MainWindow 的 Activated 事件的事件处理程序中调用。
    /// /// 关闭键盘。 /// /// 如果设置为 true [恢复文本]。 公共无效 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 中使用行为和复合命令的知识......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-16
      • 2012-07-17
      相关资源
      最近更新 更多