0

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

4

1 回答 1

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 [恢复文本]。public void CloseKeyboard(bool revertText = false) { lock (_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 中使用行为和复合命令的知识......

于 2013-02-18T02:10:32.780 回答