wpf - 控制初始化顺序惨败

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

Slider 将在初始化过程中引发其 ValueChanged 事件,而 counter 仍为 null

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

处理这个问题最优雅的方法是什么?这个特定示例应该使用数据绑定(bind)这一事实不是重点。

最佳答案

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

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

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,在 LoadedRenderDataBind 操作之后运行

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

关于wpf - 控制初始化顺序惨败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9535810/

相关文章:

wpf - 使用 Mahapps.Metro 在 WPF 中设计汉堡菜单

javascript - 在循环中附加事件 (IE 7)

javascript - 如何在 Google Apps 脚本中异步运行方法?

c - 如何初始化一个(复杂的?)结构

c - 部分初始化 C 结构

wpf - 如何获取 WPF 弹出窗口的实际宽度

wpf - 在 WPF 中将 slider 值绑定(bind)到 slider 的高度

java - JSF selectOneMenu 值更改事件触发帮助 (Java Server Faces)

c++ - 具有可变数组大小的模板类 : initialize with array reference or brace-enclosed initializer list

wpf - 如何在 XAML 的路径中转义字符 '&'?