WPF:在附加属性中,如何等待直到视觉树正确加载?

问题描述:

我在WPF应用中有一个附加属性。

I have an Attached Property in a WPF app.

下面的代码在 OnLoad 事件中,但是,除非我添加了500毫秒的延迟,否则该方法将不起作用。

The code below is inside the OnLoad event, but it doesn't work unless I add a hacky 500 millisecond delay in.

是否有某种方法可以避免这种延迟,并检测可视化树何时已加载?

Is there some way to avoid this delay, and detect when the visual tree has been loaded?

private static void FrameworkElement_Loaded(object sender, RoutedEventArgs e)
{
    // ... snip...
    Window window = GetParentWindow(dependencyObject);

    // Without this delay, changing properties does nothing.
    Task task = Task.Run(
        async () =>
        {
            {
                // Without this delay, changing properties does nothing.
                await Task.Delay(TimeSpan.FromMilliseconds(500));

                Application.Current.Dispatcher.Invoke(
                    () =>
                    {
                        // Set False >> True to trigger the dependency property.
                        window.Topmost = false;
                        window.Topmost = true;                                              
                    });
            }
        });
 }



更新1



按照@Will的回答,使用调度程序并选择适当的优先级。

Update 1

As per the answer from @Will, "use the dispatcher and select the appropriate priority". This works brilliantly:

private static void FrameworkElement_Loaded(object sender, RoutedEventArgs e)
{
   // Wrap *everything* in a Dispatcher.Invoke with an appropriately
   // low priority, to defer until the visual tree has finished updating.
   Application.Current.Dispatcher.Invoke(
   async () =>
        {
            // This puts us to the back of the dispatcher queue.
            await Task.Yield();

            // ... snip...
            Window window = GetParentWindow(dependencyObject);

            window.Topmost = true;                                              
        }, 
        // Use an appropriately low priority to defer until 
        // visual tree updated.
        DispatcherPriority.ApplicationIdle);
 }



更新2



如果使用DevExpress,则 LayoutTreeHelper 类对于在可视树的上下扫描很有用。

Update 2

If using DevExpress, the LayoutTreeHelper class is useful for scanning up and down the visual tree.

有关处理可视树上下扫描的示例代码,请参见:

For sample code that deals with scanning up and down the visual tree, see:

  • DevExpress: In an attached property, how to wait until we are 100% sure that DevExpress has finished building its Visual Tree?
  • DevExpress and How to ensure that a LayoutPanel is always in front of everything else?

如果您在附属物业中,可靠加载视觉树的唯一方法是在 Loaded 事件处理程序中或之后执行代码。如果我们不了解此限制,那么一切都会间歇性地失败。如上所述,等到触发 OnLoaded 事件之后,这种尝试远远优于尝试引入其他随机形式的延迟的任何其他方法。

If you are in an attached property, the only way to reliably load the visual tree is to execute the code in or after the Loaded event handler. If we are not aware of this limitation, then everything will fail intermittently. Waiting until after the OnLoaded event has fired is far superior to any other method that attempts to introduce other random forms of delays, as noted above.

如果您使用的是DevExpress,这甚至更关键:在某些情况下,尝试在 Loaded 事件之前做任何事情都可能导致崩溃。

If you are using DevExpress, this is even more critical: attempting to do anything before the Loaded event can, in some circumstances, result in a crash.

例如:


  • 调用窗口。 ()在某些情况下导致 Loaded 事件导致崩溃。

  • 加入该事件 IsVisibleChanged 的处理程序在 Loaded 事件之前会导致崩溃。

  • Calling window.Show() before the Loaded event has resulted in a crash in some circumstances.
  • Hooking into the event handler for IsVisibleChanged before the Loaded event has result in a crash in some circumstances.

免责声明:我与DevExpress不相关,它是许多不错的WPF库之一,我还建议使用Infragistics 。

如果要等待在UI线程中做某事,请使用 Dispatcher 。你怎么抓它?真是骗人

If you want to wait to do something in the UI thread, use the Dispatcher. How do you snag it? That's a dupe.

如何我会得到UI线程分派器吗?

您可以使用 DispatcherPriority 以选择将来的时间。优先级基于UI活动,因此,例如,下周您就无法说了。但是例如,您可以说让我等到绑定被处理之后。

You can use the DispatcherPriority to select a time in the future. Priorities are based on UI activities, so you can't say, for example, next week. But you can say "let me wait until after bindings have been processed", for example.