2

考虑以下代码:

<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事件,而is still 。counternull

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

处理这个问题的最优雅的方法是什么?这个特定示例应该使用数据绑定这一事实是无关紧要的。

4

2 回答 2

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在 UI 线程上以不同的DispatcherPriority运行事件。默认值为Normal, 在Loaded,RenderDataBind操作之后运行

Dispatcher.BeginInvoke(DispatcherPriority.DataBind, 
    new Action(delegate() { counter.Text = e.NewValue.ToString(); }));
于 2012-03-02T16:36:37.030 回答
2

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

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

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

于 2013-04-29T17:02:15.473 回答