Dispatcher 仅在第一次调用时更新 UI
Dispatcher only updates UI the first time it's called
我有一个 class 执行一个可能很长的 运行ning 操作,所以它通过触发一个事件来报告它的进度,我计划 运行 它在一个单独的来自 UI 的线程。为了测试状态消息事件将按计划更新数据绑定列表框,我制作了一个具有相同事件类型的虚拟 class:
class NoisyComponent
{
public EventHandler<string> OnProgress;
protected void prog(params string[] msg)
{
if (OnProgress != null)
OnProgress(this, string.Join(" ", msg));
}
public void Start(int lim)
{
for (int i = 0; i < lim; i++)
{
prog("blah blah blah", i.ToString());
System.Threading.Thread.Sleep(200);
}
}
}
我正在测试的页面有一个列表框:
<ListBox ItemsSource="{Binding Path=appstate.progress_messages, Source={x:Static Application.Current}}"></ListBox>
我在 OnRender 中开始任务:
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var noisy = new NoisyComponent();
noisy.OnProgress += (sender, msg) =>
{
Dispatcher.Invoke(() =>
{
(App.Current as App).appstate.progress_messages.Add(msg);
UpdateLayout();
});
};
Task.Run(() => { noisy.Start(5); });
}
appstate.progress_messages
是依赖项 属性
public List<string> progress_messages
{
get { return (List<string>)GetValue(progress_messagesProperty); }
set { SetValue(progress_messagesProperty, value); }
}
public static readonly DependencyProperty progress_messagesProperty =
DependencyProperty.Register("progress_messages", typeof(List<string>), typeof(AppState), new PropertyMetadata(new List<string>()));
我希望每 200 毫秒在列表框中看到一个新的 "blah blah blah #" 行,但我只看到第一行 ("blah blah blah 0") 而没有其他任何内容。我在 Dispatcher.Invoke
lambda 中设置了一个断点,它肯定多次获得 运行,并且 属性 正在更新,但它没有显示在 UI.
我认为问题可能是因为 属性 是一个列表,它只被分配一次,然后在现有对象上调用 Add
方法,并且更改没有被依赖 属性 "detected"。但到目前为止,我没有发现如果依赖项 属性 是一个集合,则需要执行特殊步骤。
我做错了什么?
我不确定,但是...
尝试制作 progress_messages 一个 ObservableCollection
public ObservableCollection<string> progress_messages
{
get { return (ObservableCollection<string>)GetValue(progress_messagesProperty); }
set { SetValue(progress_messagesProperty, value); }
}
public static readonly DependencyProperty progress_messagesProperty =
DependencyProperty.Register("progress_messages", typeof(ObservableCollection<string>), typeof(AppState), new PropertyMetadata(new ObservableCollection<string>()));
我有一个 class 执行一个可能很长的 运行ning 操作,所以它通过触发一个事件来报告它的进度,我计划 运行 它在一个单独的来自 UI 的线程。为了测试状态消息事件将按计划更新数据绑定列表框,我制作了一个具有相同事件类型的虚拟 class:
class NoisyComponent
{
public EventHandler<string> OnProgress;
protected void prog(params string[] msg)
{
if (OnProgress != null)
OnProgress(this, string.Join(" ", msg));
}
public void Start(int lim)
{
for (int i = 0; i < lim; i++)
{
prog("blah blah blah", i.ToString());
System.Threading.Thread.Sleep(200);
}
}
}
我正在测试的页面有一个列表框:
<ListBox ItemsSource="{Binding Path=appstate.progress_messages, Source={x:Static Application.Current}}"></ListBox>
我在 OnRender 中开始任务:
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var noisy = new NoisyComponent();
noisy.OnProgress += (sender, msg) =>
{
Dispatcher.Invoke(() =>
{
(App.Current as App).appstate.progress_messages.Add(msg);
UpdateLayout();
});
};
Task.Run(() => { noisy.Start(5); });
}
appstate.progress_messages
是依赖项 属性
public List<string> progress_messages
{
get { return (List<string>)GetValue(progress_messagesProperty); }
set { SetValue(progress_messagesProperty, value); }
}
public static readonly DependencyProperty progress_messagesProperty =
DependencyProperty.Register("progress_messages", typeof(List<string>), typeof(AppState), new PropertyMetadata(new List<string>()));
我希望每 200 毫秒在列表框中看到一个新的 "blah blah blah #" 行,但我只看到第一行 ("blah blah blah 0") 而没有其他任何内容。我在 Dispatcher.Invoke
lambda 中设置了一个断点,它肯定多次获得 运行,并且 属性 正在更新,但它没有显示在 UI.
我认为问题可能是因为 属性 是一个列表,它只被分配一次,然后在现有对象上调用 Add
方法,并且更改没有被依赖 属性 "detected"。但到目前为止,我没有发现如果依赖项 属性 是一个集合,则需要执行特殊步骤。
我做错了什么?
我不确定,但是...
尝试制作 progress_messages 一个 ObservableCollection
public ObservableCollection<string> progress_messages
{
get { return (ObservableCollection<string>)GetValue(progress_messagesProperty); }
set { SetValue(progress_messagesProperty, value); }
}
public static readonly DependencyProperty progress_messagesProperty =
DependencyProperty.Register("progress_messages", typeof(ObservableCollection<string>), typeof(AppState), new PropertyMetadata(new ObservableCollection<string>()));