Событие WPF, которое запускается после того, как элемент полностью переписан, но до его организации - PullRequest
1 голос
/ 04 июля 2010

Я пишу элемент управления WPF, который динамически изменяет его содержимое в зависимости от того, какие типы потомков Window / UserControl находятся в его списке происхождения (часть эксперимента с соглашением или конфигурацией).

Как таковой, мне нужен некоторый код для запуска после того, как мой элемент управления полностью переписан (т. Е. Вплоть до отображаемого окна). В идеале я также хотел бы, чтобы мой код выполнялся до первого прохода Measure / Arrange, поскольку мой код изменит содержимое элемента управления и инициирует другой проход Measure / Arrange.

Я посмотрел на EndInit, но он срабатывает после загрузки элемента управления из XAML, и в этот момент он может быть не полностью родственным. (Например, если мой элемент управления находился в элементе управления UserControl, EndInit сработает после загрузки элемента управления UserControl, но до того, как он будет связан с чем-либо другим. Я хочу подождать, пока элемент управления UserControl не будет связан с чем-то, а это связано с чем-то другим, весь путь вверх.)

В настоящее время я просто подключаю событие Loaded к конструктору моего элемента управления и запускаю там свой код (как ни странно, в WPF нет метода переопределения OnLoaded):

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

Это работает - оно срабатывает, когда родители полностью заселены - но это немного меньше, чем оптимальное, потому что есть проход измерения / упорядочения, который происходит до Loaded.

Есть ли хорошее место, где я мог бы разместить свой код так, чтобы он запускался после того, как Parents настроен полностью, но до первого прохода Measure / Arrange?

Дополнительные баллы за решения, которые также будут работать в Silverlight, ElementHost, конструкторе Blend / VS и VisualBrush (т. Е. Не предполагая, что родительский элемент верхнего уровня является Window, или в случае VisualBrush, не предполагая, что там даже является родителем - просто он такой же родительский, каким он будет до того, как появится на экране, или будет отправлен на принтер, или еще что-нибудь).

1 Ответ

0 голосов
/ 04 июля 2010

Я полагаю, что все родители настроены в одной операции диспетчера, поэтому вы должны иметь возможность получить такое поведение, поместив свою логику в делегат и поставив ее в очередь в качестве следующей операции диспетчера после установки родителя:

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...