gre*_*man 14 c# data-binding wpf multithreading
这是我之前的问题的延续
但是,由于Jon对这个问题有了新的认识,我将不得不完全重写原始问题,这会使该主题难以理解.所以,新的,非常具体的问题.
两件:
当前情况 - 库发送了很多关于数据更改的通知,尽管它在自己的线程中工作,它完全阻塞了WPF数据绑定机制,结果不仅监视数据不起作用(它没有刷新),但整个GUI被冻结在处理数据时.
目标 - 精心设计,抛光的方式使GUI保持最新 - 我并不是说它应该立即显示数据(它甚至可以跳过一些变化),但它在计算时不能冻结.
这是简化的示例,但它显示了问题.
XAML部分:
<StackPanel Orientation="Vertical">
<Button Click="Button_Click">Start</Button>
<TextBlock Text="{Binding Path=Counter}"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
C#部分(请注意这是一个代码,但有两个部分):
public partial class MainWindow : Window,INotifyPropertyChanged
{
// GUI part
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var thread = new Thread(doProcessing);
thread.IsBackground = true;
thread.Start();
}
// this is non-GUI part -- do not mess with GUI here
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string property_name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property_name));
}
long counter;
public long Counter
{
get { return counter; }
set
{
if (counter != value)
{
counter = value;
OnPropertyChanged("Counter");
}
}
}
void doProcessing()
{
var tmp = 10000.0;
for (Counter = 0; Counter < 10000000; ++Counter)
{
if (Counter % 2 == 0)
tmp = Math.Sqrt(tmp);
else
tmp = Math.Pow(tmp, 2.0);
}
}
}
Run Code Online (Sandbox Code Playgroud)
(请不要将它们作为答案重新发布)
我按照我喜欢的解决方法排序列表,即它需要多少工作,限制等等.
我目前的"解决方案"是在主循环中添加Sleep.减速可以忽略不计,但它足以刷新WPF(所以它甚至比每次通知之前的睡眠更好).
我真的很聆听真正的解决方案,而不是一些技巧.
备注
备注放弃数据绑定 - 对我而言,它的设计被破坏,在WPF中你有单一的通信渠道,你不能直接绑定到变更的来源.数据绑定根据名称过滤源(字符串!).即使您使用一些聪明的结构来保留所有字符串,这也需要一些计算.
编辑:关于抽象的评论 - 叫我老计时器,但我开始学习计算机说服,计算机应该帮助人类.重复性任务是计算机领域,而不是人类.无论你怎么称呼它 - MVVM,抽象,接口,单继承,如果你一遍又一遍地编写相同的代码,并且你没有办法自动化你所做的事情,你就会使用破坏的工具.所以例如lambda是伟大的(对我来说工作较少),但单继承不是(对我来说更多的工作),数据绑定(作为一个想法)是伟大的(较少的工作),但我需要绑定到每个库的代理层是破碎的想法,因为它需要大量的工作.
在我的WPF应用程序中,我不直接将属性更改从模型发送到GUI.它总是通过代理(ViewModel).
属性更改事件放在队列中,该队列从计时器上的GUI线程读取.
不明白这是多么多的工作.您只需要另一个用于模型的propertychange事件的侦听器.
使用"Model"属性创建一个ViewModel类,该属性是您当前的datacontext.将数据绑定更改为"Model.Property"并添加一些代码以挂钩事件.
它看起来像这样:
public MyModel Model { get; private set; }
public MyViewModel() {
Model = new MyModel();
Model.PropertyChanged += (s,e) => SomethingChangedInModel(e.PropertyName);
}
private HashSet<string> _propertyChanges = new HashSet<string>();
public void SomethingChangedInModel(string propertyName) {
lock (_propertyChanges) {
if (_propertyChanges.Count == 0)
_timer.Start();
_propertyChanges.Add(propertyName ?? "");
}
}
// this is connected to the DispatherTimer
private void TimerCallback(object sender, EventArgs e) {
List<string> changes = null;
lock (_propertyChanges) {
_Timer.Stop(); // doing this in callback is safe and disables timer
if (!_propertyChanges.Contain(""))
changes = new List<string>(_propertyChanges);
_propertyChanges.Clear();
}
if (changes == null)
OnPropertyChange(null);
else
foreach (string property in changes)
OnPropertyChanged(property);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13631 次 |
| 最近记录: |