考虑以下代码:
<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
,在 Loaded
、Render
和 DataBind
操作之后运行
Dispatcher.BeginInvoke(DispatcherPriority.DataBind,
new Action(delegate() { counter.Text = e.NewValue.ToString(); }));
关于wpf - 控制初始化顺序惨败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9535810/