Какое последнее событие сработало при загрузке нового окна WPF / C #? - PullRequest
19 голосов
/ 16 ноября 2009

Я пытаюсь загрузить окно настроек для своего приложения, и я хотел бы, чтобы кнопка «Применить» изначально была отключена, а затем при обновлении настроек кнопка «Применить» снова включается. У меня есть некоторые данные управления, связанные с объектом предпочтений, и что после загрузки окна, запускаются события выпадающего списка. Есть ли какое-нибудь событие, которое гарантированно произойдет в последний раз после того, как все станет стабильным?

Вот как выглядит мой код (кнопка «Применить» всегда активируется после загрузки окна):

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    _preferencesData = new PreferencesDataContext();
    LayoutRoot.DataContext = _preferencesData;
    ButtonApply.IsEnabled = false;
}

private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
    ButtonApply.IsEnabled = true;
}

Интересно также отметить, что это происходит только с текстовыми полями и комбинированными списками, а не с флажками или радиокнопками.

Ответы [ 7 ]

53 голосов
/ 17 ноября 2009

Лучшее решение для простых нужд

Ответ Джозефа - лучшее решение для вашей простой задачи: просто используйте привязку данных и позвольте модели данных справиться с этим.

Ответ на поставленный вопрос

Существуют более сложные сценарии, когда вам действительно нужен контроль после того, как абсолютно все закончило загрузку и все события сработали. Не существует единственного события, которое происходит «мертвым в последнюю очередь», но легко эффективно выполнить собственное событие, используя очередь Диспетчера.

Вот как это сделать:

Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() =>
{
  var x = ComputeSomething(1, 2, 3);
  DoSomething(x, "Test");
}));

Все внутри {} будет выполнено, когда WPF завершит все с более высоким приоритетом, чем ContextIdle, который включает все обработчики событий, загруженные события, входные события, рендеринг и т. Д.

Последовательность событий при создании и отображении окна

В соответствии с запросом приведена последовательность основных событий в WPF при создании и отображении окна:

  1. Конструкторы и геттеры / сеттеры вызываются при создании объектов, включая PropertyChangedCallback, ValidationCallback и т. Д. Для обновляемых объектов и любых объектов, которые наследуются от них

  2. Когда каждый элемент добавляется в визуальное или логическое дерево, запускается его Инициализированное событие, которое приводит к тому, что стили и триггеры применяются в дополнение к любой инициализации, специфичной для элемента, которую вы можете определить [примечание: инициализированное событие не запускается для листьев в логическом дереве, если в его корне нет PresentationSource (например, Window)]

  3. Окно и все неразвернутые визуальные элементы в нем измеряются, что вызывает шаблон ApplyTemplate для каждого элемента управления, который вызывает дополнительную конструкцию дерева объектов, включая дополнительные конструкторы и методы получения / установки

  4. Окно и все не свернутые визуальные эффекты на нем расположены

  5. Окно и его потомки (логические и визуальные) получают событие Loaded

  6. Все привязки данных, которые не удалось установить при первой установке, повторяются

  7. Окну и его потомкам предоставляется возможность визуально визуализировать их содержимое

Шаги 1-2 выполняются при создании окна, независимо от того, отображается оно или нет. Другие шаги обычно не выполняются до тех пор, пока не появится окно, но они могут произойти раньше, если их запустить вручную.

11 голосов
/ 03 ноября 2011

Событие Window.ContentRendered удовлетворяет моим требованиям.

11 голосов
/ 16 ноября 2009

Я только что сделал то же самое с поведением в приложении Systray WPF.

Однако я не делал этого, используя обработку событий. Я просто связал свойство Enabled моей кнопки со свойством в моей ViewModel и обновлял свойство всякий раз, когда мне нужно было поведение.

5 голосов
/ 16 ноября 2009

Вы можете использовать ManagedSpy, чтобы понять это самостоятельно.

http://msdn.microsoft.com/en-us/magazine/cc163617.aspx

1 голос
/ 17 ноября 2009

Не для того, чтобы бросать в вас много вещей, с которыми вы можете или не можете быть знакомы, но если это относительно новая кодовая база, вы можете рассмотреть возможность использования шаблона MVVM и использования Команды вместо архаичной (выделенной шахты) модели событий.

1 голос
/ 17 ноября 2009

Установка DataContext, скорее всего, вызовет событие SelectionChanged, и вы не можете рассчитывать, когда именно он будет запущен. Некоторая логическая проверка того, что именно выбрано, будет более надежной:

private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
    if (myComboBox.SelectedItem == null) 
    { 
      buttonApply.IsEnabled = false;
    }
    else 
    {
      buttonApply.IsEnabled = true;
    }
}

Причина, по которой это происходит потом с вашим кодом «как есть», заключается в том, что событие помещается в очередь в потоке пользовательского интерфейса, поэтому Windows может выполнить следующую строку кода в Load или обработать другие события в очереди.

0 голосов
/ 17 ноября 2009

Порядок событий в Windows Forms

Control.HandleCreated

Control.BindingContextChanged

Form.Load

Control.VisibleChanged

Form.Activated

Form.Shown

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...