【问题标题】:What is the last event to fire when loading a new WPF/C# window?加载新的 WPF/C# 窗口时触发的最后一个事件是什么?
【发布时间】:2009-11-16 20:46:58
【问题描述】:

我正在尝试为我的应用程序加载首选项窗口,并且我希望最初禁用应用按钮,然后在更新首选项时,再次启用应用按钮。我有一些控件数据绑定到首选项对象,发生的情况是 窗口加载后,组合框事件被触发。有没有什么事情是在一切都稳定之后才保证最后发生的?

这是我的代码的样子(应用按钮总是在窗口加载后启用):

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

有趣的是,这仅发生在文本框和组合框上,而不是复选框或单选按钮。

【问题讨论】:

  • 感谢所有伟大的建议。我最终将一个名为“IsDirty”的字段添加到我的首选项数据对象中,然后我将应用按钮的 IsEnabled 属性绑定到该字段。通过这种方式,我按照 Joseph 和 ascalonx 的建议一起消除了所有事件。

标签: c# wpf events


【解决方案1】:

简单需求的最佳解决方案

Joseph 的回答是迄今为止满足您简单需求的最佳解决方案:只需使用数据绑定并让数据模型处理即可。

按提出的问题回答

还有一些更复杂的场景,在所有内容都完成加载并且所有事件都已触发之后,您确实需要控制。没有任何一个事件是“最后一个”发生的,但是使用 Dispatcher 队列很容易有效地滚动您自己的事件。

这是怎么做的:

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

当 WPF 以高于 ContextIdle 的优先级完成所有内容时,将执行 { } 中的所有内容,包括所有事件处理程序、加载的事件、输入事件、渲染等。

创建和显示窗口时的事件序列

根据要求,以下是创建和显示窗口时 WPF 中的主要事件序列:

  1. 在创建对象时调用构造函数和 getter/setter,包括正在更新的对象以及从它们继承的任何对象上的 PropertyChangedCallback、ValidationCallback 等

  2. 随着每个元素被添加到可视化或逻辑树中,它的 Intialized 事件被触发,这会导致除了您可以定义的任何特定于元素的初始化之外,还发现应用了样式和触发器 [注意:未触发初始化事件如果根没有 PresentationSource(例如窗口),则在逻辑树中的叶子]

  3. 窗口及其上所有未折叠的视觉对象都是测量的,这会在每个控件上产生一个 ApplyTemplate,这会导致额外的对象树构造,包括更多的构造函数和 getter/setter

  4. 窗口及其上所有未折叠的视觉对象均已排列

  5. 窗口及其后代(逻辑和视觉)接收到 Loaded 事件

  6. 任何在首次设置时失败的数据绑定都会重试

  7. 窗口及其后代有机会以可视方式呈现其内容

步骤 1-2 在创建窗口时完成,无论它是否显示。其他步骤通常在显示窗口之前不会发生,但如果手动触发它们可以更早发生。

【讨论】:

  • 您拼错了 Invoke 并且在分号前缺少了一个右括号,否则,谢谢!
  • 我会考虑“加载”优先级而不是“上下文空闲”。在这种情况下,方法在布局和渲染完成时处理,但在输入优先级的项目被服务之前。
  • 太棒了。非常感谢!!
【解决方案2】:

Window.ContentRendered 事件满足了我的要求。

【讨论】:

    【解决方案3】:

    我只是在系统托盘 WPF 应用程序中做了同样的事情。

    但是,我没有使用事件处理来做到这一点。我只是将按钮的 Enabled 属性绑定到 ViewModel 中的一个属性,并在我需要该行为时更新该属性。

    【讨论】:

      【解决方案4】:

      您可以使用 ManagedSpy 自行解决。

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

      【讨论】:

        【解决方案5】:

        设置 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 线程上排队,所以它是否会执行Load 中的下一行代码,或者处理队列中的其他事件。

        【讨论】:

          【解决方案6】:

          不要向你扔一大堆你可能熟悉或不熟悉的东西,但如果这是一个相对较新的代码库,你可能需要考虑使用 MVVM 模式并使用 Commands 而不是 古老的(强调我的)事件模型。

          【讨论】:

            【解决方案7】:

            Order of Events in Windows Forms

            Control.HandleCreated

            Control.BindingContextChanged

            Form.Load

            Control.VisibleChanged

            Form.Activated

            Form.Shown

            【讨论】:

            • 与问题无关,因为他在问 WPF 而你在谈论 WinForms。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-05-27
            • 2015-12-05
            • 1970-01-01
            • 2016-10-21
            • 2016-06-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多