在元素完全成为父级之后触发的WPF事件,但在它被安排之前

时间:2010-07-04 14:43:18

标签: wpf

我正在编写一个WPF控件,它根据Windowage / UserControl后代在其父级列表中的类型动态地更改其内容(具有约定与配置的实验的一部分)。

因此,我需要一些代码才能在我的控件完全成为父级之后运行(即一直到正在显示的Window)。理想情况下,我还希望我的代码在第一个Measure / Arrange传递之前运行,因为我的代码将更改控件的内容并强制执行另一个Measure / Arrange传递。

我已经查看了EndInit,但是在从XAML加载控件后它会触发,此时它可能不是完全的父级。 (例如,如果我的控件是在UserControl上,那么一旦UserControl被加载,EndInit就会触发 - 但在它成为其他任何东西之前。我想等到UserControl成为某些东西,并且这是其他东西的父级,一直以来。)

目前我只是从我的控件的构造函数中挂起Loaded事件,并在那里运行我的代码(奇怪的是,WPF没有OnLoaded方法来覆盖):

public class MyControl
{
    public MyControl()
    {
        Loaded += (sender, e) => { ... };
    }
}

这样做 - 它会在父母完全填充时触发 - 但它略微不是最佳的,因为在加载之前会有一个测量/排列传递。

我是否有一个好的地方可以放置我的代码,以便在父母一直设置完毕后,但在第一次测量/安排通过之前运行?

可以在Silverlight,ElementHost,Blend / VS设计器和VisualBrush中使用的解决方案的额外酷点(即,不假设顶级父级是Window,或者在VisualBrush的情况下,不假设那里甚至一个父母 - 只是它是在出现在屏幕上,或者被发送到打印机之前,或者其他任何东西的父母。

1 个答案:

答案 0 :(得分:0)

我相信父项都设置在一个调度程序操作中,因此您应该能够通过将您的逻辑放在委托中并将其排队作为父项设置后的下一个调度程序操作来获得该行为:

protected override void OnVisualParentChanged(DependencyObject oldParent)
{
    base.OnVisualParentChanged(oldParent);
    this.Dispatcher.BeginInvoke(new Action(OnReady));
}

private void OnReady()
{
    // Element should be fully parented here
}

如果你想要处理没有父母的情况,你也可以从EndInit而不是OnVisualParentChanged执行此操作,尽管EndInit似乎被多次调用所以你需要检查重复:

private bool readyQueued;

public override void EndInit()
{
    base.EndInit();
    if (!readyQueued)
    {
        this.Dispatcher.BeginInvoke(new Action(OnReady));
        readyQueued = true;
    }
}

private void OnReady()
{
    readyQueued = false;
    // Element should be fully parented here
}