15

这是一个奇怪的问题,只有在 Win8.1 中。

众所周知,如果一台机器上有一个正在运行的应用程序,当我们通过远程桌面连接连接/断开/重新连接到这台机器时,不应该有任何其他针对该应用程序的行为。但是,我们发现当我们使用 RDC 关闭并重新连接到机器时,Win8.1 会向 WPF 应用程序触发卸载和加载事件。这是一种不受欢迎的行为,可能会导致错误。

以下是稳定的重现步骤:

  1. 编写一个 WPF 应用程序,其中包含一个按钮并处理该按钮的卸载和加载事件。
  2. 例如,使用 RDC 从 Win7 连接到 Win8.1。
  3. 在远程桌面上,运行这个 WPF 应用程序。(加载事件将记录在 a.txt 中)。
  4. 单击“x”关闭 RDC。
  5. 再次连接到这个Win8.1。
  6. 您将看到卸载和加载事件已被触发。

如果 WPF 应用程序在 Win7 或 Win server 2008 中运行,则不会触发这些事件。

所以,我认为这是 Win8.1 中不受欢迎的行为。这是Win8.1 RDP中的错误吗?或者这是一个新功能?

4

1 回答 1

7

这是因为重新连接 RDP 会通知 WPF 代码会话和屏幕已更改。WPF 需要重建其 DirectX 资源并可能处理更新的屏幕尺寸(即使分辨率可能相同)。这很有意义,因为 RDP 客户端可以从 RDP“体验”选项卡中指定不同的功能,例如图形级别和其他属性。WPF 不会确定参数是否与上次发生连接时的参数相同,它会触发新的渲染和布局周期(因为颜色和屏幕分辨率可能已更改,所以很有意义)。这会导致重新加载控件并触发新的 Loaded 事件。

通过检查 .NET 源代码中的 HwndTarget.cs,您可以看到很多血腥细节。在此文件中搜索“会话”,您会看到很多会话断开/重新连接的处理。

http://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Interop/HwndTarget.cs,f20f989ef219e391

如果你想找到一种方法来避免在加载/卸载代码中做额外的工作,你可能必须将它移动到一个函数,你确保你只通过标志或空检查调用一次。

您可以通过在 Loaded 事件处理程序上添加断点并转到工具 > 选项、调试并取消选中“仅启用我的代码”,然后选中“启用 .NET 框架源步进”并选中“启用源服务器”来见证发生了什么支持。当您连接 RDP 时,bkpt 将触发,调用堆栈将在其他级别的调用中显示调整大小事件。这可能是由于 WPF 也获得了 WM_DISPLAYCHANGE 并重新布局所有内容,以防此连接或多或少有分辨率。

于 2017-07-07T12:09:35.147 回答