控制初始化订单Fiasco

时间:2012-03-02 15:24:42

标签: wpf events initialization initialization-order

请考虑以下代码:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <Slider ValueChanged="slider_ValueChanged/>
        <TextBox x:Name="counter"/>
    </StackPanel>
</Window>

namespace Project1
{
    public partial class Window1 : Window
    {
        public MainWindow() { InitializeComponent(); }

        void slider_ValueChanged(object sender,
            RoutedPropertyChangedEventArgs<double> e)
        {
            counter.Text = e.NewValue.ToString();
        }
    }
}

ValueChanged仍为counter时,幻灯片会在初始化期间提升其null事件

这是我使用WPF遇到的一个更大问题的一个例子,UI事件可以随时触发,而且没有一个地方可以放置我的初始化代码,以确保它能够运行在WPF系统拥有的所有指针都已初始化之后但在任何UI事件被触发之前。

处理这个问题最优雅的方法是什么?这个具体的例子应该使用数据绑定的事实不是重点。

2 个答案:

答案 0 :(得分:3)

根据您的具体情况,有很多方法可以解决这个问题

首先,你可以简单地认识到对象可能没有被初始化并在处理之前检查它。例如,

if (counter.Text != null)
    counter.Text = e.NewValue.ToString();

其次,您可以将事件附加到对象的Loaded事件中,这样它们就不会在对象初始化之后才会触发。

void Counter_Loaded(object sender, EventArgs e)
{
    slider.ValueChanged += Slider_ValueChanged;
}

void Counter_Unloaded(object sender, EventArgs e)
{
    slider.ValueChanged -= Slider_ValueChanged;
}

最后,您可以使用WPF的Dispatcher在不同DispatcherPriority的UI线程上运行事件。默认值为Normal,在LoadedRenderDataBind操作后运行

Dispatcher.BeginInvoke(DispatcherPriority.DataBind, 
    new Action(delegate() { counter.Text = e.NewValue.ToString(); }));

答案 1 :(得分:2)

此问题的 true 答案是使用MVVM模式,其中文件后面的窗口代码几乎没有初始化代码。

在此模式中,UI仅与数据绑定连接到其余代码。您编写了实现INotifyPropertyChanged的特殊视图模型类,并将您的业务逻辑公开,并将其作为UI绑定的一系列属性公开。

当然,您可以完全控制视图模型的初始化方式。