控制初始化命令Fiasco



考虑以下代码:

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

Slider将在初始化期间引发其ValueChanged事件,而counter仍为null

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

处理此问题最优雅的方法是什么这个特定的例子应该使用数据绑定,这一点无关紧要。

根据您的情况,有很多方法可以处理

首先,您可以简单地识别对象可能未初始化的事实,并在处理之前进行检查。例如,

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

这个问题的true答案是使用MVVM模式,其中文件后面的窗口代码几乎不包含初始化代码。

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

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

相关内容

  • 没有找到相关文章