WPF中是否有“所有子元素加载完成”事件?

44

我正在监听页面的加载事件。该事件首先触发,然后所有子元素都会触发它们的加载事件。我需要一个在所有子元素都加载完成时触发的事件。这种事件存在吗?

7个回答

63

我明白您的意思。在WPF中,我也想要一个开箱即用的解决方案。

有时候您需要在所有子控件加载完成后执行某些代码。

将以下代码放入父控件的构造函数中:

Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => {code that should be executed after all children are loaded} ));

迄今为止帮了我几次。


那个很好用。在我看来,WPF UserControl API 应该包括一个 PostLoaded 事件,在所有控件加载完成后触发,以复制这个实现。 - Mike
有没有其他的解决方案?看起来调度程序无缘无故地重复触发,而且调试起来很困难 :( - Piotr Golacki

12

Loaded是在所有子元素Initialized之后触发的事件。据我所知,没有AfterLoad事件。如果可以的话,请将子元素的逻辑移动到Initialized事件中,然后Loaded事件会在它们全部初始化后发生。

请参阅MSDN - 对象生命周期事件


5
如果一个回答是错误的,怎么可能有7个赞成?只有2个赞成的Buckly的回答却完全可行。 - Frederik Prijck
1
@FrederikPrijck 只因为一个答案是正确的并不意味着另一个答案不正确。这个答案是正确的,有用的,而且正是我所需要的——我在子项的Loaded处理程序中做了一些应该在其Initialized处理程序中完成的事情。实际上,Buckley的答案说“WPF中缺少开箱即用的解决方案”,与这个答案是一致的。请看Jobi的答案,它表明有些情况下Buckey的hack将不足够。 - Jim Balter
我在哪里说只有一个答案是正确的?这个答案对我没用,但这完全不同于说只有一个答案是正确的。但已经过了一段时间,所以我不知道细节了。 - Frederik Prijck
@FrederikPrijck,因为您和投票给您的5个人都是错误的吗?_The Loaded event and the Initialized event, MSDN_ - user585968
如果父元素需要获取精确的子元素渲染大小,则此方法无效。 - Hrvoje Batrnek


0

其中一个选项(当内容呈现时):

this.LayoutUpdated += OnLayoutUpdated;

private void OnLayoutUpdated(object sender, EventArgs e)
            {
                if (!isInitialized && this.ActualWidth != 0 && this.ActualHeight != 0)
                {
                    isInitialized = true;
                    // Logic here
                }
            };

0

在你想要等待的 xaml 组件内,加入一个加载事件 Loaded="MyControl_Loaded",如下所示:

<Grid Name="Main" Loaded="Grid_Loaded"...>
<TabControl Loaded="TabControl_Loaded"...>
<MyControl Loaded="MyControl_Loaded"...>
...

在你的代码

bool isLoaded;

private void MyControl_Loaded(object sender, RoutedEventArgs e)
{
   isLoaded = true;
}

然后,在事件触发器内,如果要执行某些操作但在所有组件正确加载之前就已经触发,请添加if(!isLoaded) return;

private void OnButtonChanged(object sender, RoutedEventArgs e)
{
    if(!isLoaded) return;

    ... // code that must execute on trigger BUT after load
}

0

由于大多数情况下数据决定是否加载特定子项到VisualTree中(例如DataTemplate中的UI元素),因此WPF无法提供那种事件。

因此,如果您能更清楚地解释您的场景,我们可以找到特定于该场景的解决方案。


-2

最终我按照这些方式做了一些事情...你的结果可能会有所不同。

void WaitForTheKids(Action OnLoaded)
{
  // After your children have been added just wait for the Loaded
  // event to fire for all of them, then call the OnLoaded delegate

  foreach (ContentControl child in Canvas.Children)
  {
    child.Tag = OnLoaded; // Called after children have loaded
    child.Loaded += new RoutedEventHandler(child_Loaded);
  }
}
internal void child_Loaded(object sender, RoutedEventArgs e)
{
  var cc = sender as ContentControl;
  cc.Loaded -= new RoutedEventHandler(child_Loaded);

  foreach (ContentControl ctl in Canvas.Children)
  {
    if (!ctl.IsLoaded)
    {
      return;
    }
  }
  ((Action)cc.Tag)();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接