2009-11-16 3 views
19

Я пытаюсь загрузить окно настроек для своего приложения, и я бы хотел, чтобы кнопка Apply сначала была отключена, а затем, когда предпочтение обновлено, кнопка Apply снова включается. У меня есть некоторые данные управления, привязанные к объекту предпочтений, и происходит то, что после окна загружаются, события combobox запускаются. Есть ли какое-либо событие, которое, как гарантируется, будет мертвым в последний раз после того, как все будет стабильным?Какое последнее событие срабатывает при загрузке нового окна WPF/C#?

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

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; 
} 

Это также интересно отметить, что это происходит только с текстовыми полями и выпадающими списками, а не флажками или радиокнопками ,

+0

Спасибо за все замечательные предложения. Я закончил тем, что добавил поле «IsDirty» в объект данных моих предпочтений, а затем связал свойство IsEnabled кнопки Apply с этим полем. Таким образом, я уничтожил все события, предложенные Джозефом и Аскалончем. –

ответ

50

Лучшее решение для простой необходимости

ответ Иосифа является лучшим решением на сегодняшний день для простой необходимости: Просто используйте привязки данных и пусть модель данных с этим справиться.

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

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

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

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

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

последовательность событий, когда окно создается и показано

в соответствии с просьбой, вот последовательность основных событий в WPF, когда окно создается и s hown:

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

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

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

  4. Окно и все незавернутые визуальные объекты на нем устроены

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

  6. Есть привязки данных, которые потерпели неудачу, когда они первый набор является повторен

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

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

+0

Вы ошибочно написали Invoke и пропустили правильный пар перед точкой с запятой, но в противном случае спасибо! –

+0

Я бы назвал приоритет «Loaded» вместо «ContextIdle». В этом случае метод обрабатывается, когда макет и рендеринг завершены, но только до того, как обслуживаются элементы с приоритетом ввода. –

+0

Amazing. Большое спасибо!! – Asheh

11

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

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

1

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

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

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

-3

Order of Events in Windows Forms

Control.HandleCreated

Control.BindingContextChanged

Form.Load

Control.VisibleChanged

Form.Activated

Form.Shown

+11

Не имеет никакого отношения к вопросу, так как он спрашивает о WPF, и вы говорите о WinForms. –

+0

WPF не winforms. – Asheh

1

Не бросить целую кучу вещей на вас, что вы можете или не можете быть знакомы, но если это относительно новая кодовое, вы можете рассмотреть вопрос об использовании шаблона MVVM и используйте Commands вместо archaic (выделение мое) eventing model.

11

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

Смежные вопросы