VisualTreeHelper::HitTest 返回不完整结果或有时没有结果的原因是什么?

huangapple go评论52阅读模式
英文:

What causes VisualTreeHelper::HitTest to return incomplete results, and sometimes no results?

问题

以下是翻译的内容:

我曾经遇到这样一种情况,我通过网络连接连接到一个Windows WPF应用程序,以便进行测试自动化的UI控制。有时,无论逻辑树或可视树的状态如何,我使用VisualTreeHelper发送请求时都没有返回结果。

这不仅仅是一个问题,更是解决问题的文档记录。

事实证明,我在检测网络连接的可用性并在其立即响应后,发出了对VisualTreeHelper的调用以捕捉UI渲染的情况。该调用的结果是不完整的,随后的调用完全失败(永远找不到任何元素)。

我的实际解决方案是在通信打开后延迟2秒,然后才第一次调用VisualTreeHelper。这消除了由于过早调用UI而引起的奇怪状态。我进行了100次应用程序重启的测试,没有任何问题。

我尝试通过谷歌搜索解决这个问题,但没有找到好的结果。

有趣的是,我向ChatGPT询问,它告诉我:
"如果您尝试在可视树完全渲染之前访问可视树的元素,可能会收到意外的结果,或者可能会引发异常。"

我请机器人告诉我它断言的信息来源,我唯一得到的链接是:
"这是一个链接,指向了Microsoft的文档,其中提到在可视树完全渲染之前调用VisualTreeHelper存在风险的信息:

https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.visualtreehelper.getchild?view=netcore-3.1#remarks"

不幸的是,这个链接实际上并没有提到这样的内容。这可能是因为ChatGPT使用的数据来自2021年,而链接的内容已经改变了。

一个朋友建议我使用archive.log(一个互联网存档)查看以前版本的链接是否包含所需的信息,但没有找到。

ChatGPT提供了相关信息,但无法提供它提炼信息的来源。

最后,我承认解决在UI完成渲染之前使用VisualTreeHelper的问题的"理想"方式是等待主窗口调用以下事件:

private void MainWindow_Loaded(object sender, RoutedEventArgs e);

并在引发此事件之前禁止使用VisualTreeHelper。我的方法不是严格的理想方式,但在付出很少努力的情况下是实际的。延迟2秒不会显著影响我的情况。

在延迟2秒后使用VisualTreeHelper等待UI渲染之后,我没有遇到任何问题。

英文:

I had a scenario where I was connecting to a Windows WPF app, through a network connection to drive UI for the purposes of test automation.
Sometimes my requests to the UI using VisualTreeHelper returned no results regardless of the apparent state of the logical or visual trees.

This, more than a question is the documentation of the solution to the problem.

It turns out that I was detecting the network connection availability and IMMEDIATELY after it responded, I issued calls that exercised VisualTreeHelper and catching the UI while being rendered. The result of that call was incomplete and subsequent calls failed completely (no elements were found ever).

My practical solution was to delay for 2 seconds between when the communication was open, and the first call to VisualTreeHelper. That eliminated the weird state caused by calling UI too soon. I tested with 100 iterations of the app rebooting with no problems.

I 'Googled' the problem but didn't find good results.

Interestingly, I asked ChatGPT about it and it informed me:
"If you try to access elements of the visual tree before they have been fully rendered, you may get unexpected results, or an exception may be thrown."

I asked the bot to tell me what sources it had for the assertion and the only link I got:
"here's a link to the Microsoft documentation that mentions the risk of calling VisualTreeHelper before the visual tree is fully rendered:

https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.visualtreehelper.getchild?view=netcore-3.1#remarks"

Unfortunately such link actually doesn't mention anything like that. This may be due to ChatGPT using 2021 data, and the link content has changed.

A friend suggested I used archive.log (an Internet archive) to see if a previous version of such link had the desired information, but none was found.

ChatGPT provided relevant information, but could not provide sources where it distilled it from.

Lastly, I acknoledge that the 'ideal' way to address the problem of racing to use VisualTreeHelper before the UI is done rendering is to wait for an event the main window calls:
private void MainWindow_Loaded(object sender, RoutedEventArgs e);
and gate any use of VisualTreeHelper until this event is raised.

My approach is not stricktly the ideal, but practical with little effort. The 2 second delay does not significantly impact my scenario.

After I delayed 2 seconds before using VisualTreeHelper to wait for UI to render, I had no problems.

答案1

得分: 1

代码部分不需要翻译。以下是翻译好的内容:

简短的答案是(正如您所观察到的),当您尝试查找控件时,它们还没有在那里。

可视树是可视树助手处理的对象图,其中包括窗口内的UI控件等。

窗口是一个内容控件。

当您实例化一个窗口时,窗口本身是使用构造函数创建的。

我不确定在可视树中是否有窗口本身的存在,但这是概念上的工作方式。

父窗口首先,然后是根面板内容和根内容。

"树"中的控件是窗口 > 内容面板 > 子控件。

构建一个窗口可能需要一些时间。2秒似乎有点慢,但开发人员倾向于在构造函数中放置各种东西。所花费的时间可能会因开发人员在其中放入多少代码、连接速度等而有所不同。

这种差异可以解释为什么测试结果会有所不同。

处理窗口的正确事件应该是"contentrendered"。正如名称所示,这个事件在窗口的所有内容都已渲染完毕后触发。

对于用户控件或页面,您可以处理"loaded"事件,但最好通过使用dispatcher来推迟处理。"Loaded"不能保证所有内容都已渲染。

英文:

The short answer is (as you have observed) that they're not there yet when you try finding the controls.

The visual tree that the visual tree helper works with is the object graph of UI controls etc which are within a window.

A window is a content control.

When you instantiate a window, the window itself is created using the constructor.

I'm not sure there's a point where there can be just the window itself in the visual tree but this is conceptually how it works.

Parent windows is first then the root panel content and the content of that root.

The "tree" of controls is window > content panel > child controls.

Constructing a window can take a while. 2 seconds seems kind of slow but developers are prone to putting all sorts of things in constructors. The time taken may vary depending on how much code the developer has put in there, connectivity speeds etc etc.

That variance would explain why a test result will vary.

The correct event to handle for a window would be contentrendered. As the name suggests, this fires after all the content of the window has been rendered.

With a usercontrol or page you can handle loaded but you're best deferring processing via use of dispatcher. Loaded doesn't guarantee everything is rendered.

huangapple
  • 本文由 发表于 2023年2月10日 06:19:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75405044.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定