假设应用程序是股票交易应用程序,后台线程监视数据更改并将其放在数据对象上.这些对象存储在绑定列表<>并实现INotifyPropertyChanged通过数据绑定将更改传播到winforms控件.
此外,数据对象当前正在通过 WinformsSynchronizationContext.Send将更改编组到UI线程.
用户能够在UI中输入一些值,这意味着可以从两面更改一些值.用户值不应该被更新覆盖.
所以我想到了几个问题:
>有没有一般的设计公民如何做(数据绑定的后台更新)?
>什么时候和如何组织UI线程?
>背景线程的最佳交互方式是什么?
绑定/数据对象?
>应该使用哪些类/接口? (BindingSource,…)
> …
我正在搜索这种情景的一般建议/设计指南…
我感谢所有的想法,链接,…
TIA
马丁
thx的想法到目前为止,但我知道Control.Invoke / BeginInvoke,…我更好地在最佳实践.作为一个附加信息,UI并不知道有一个后台线程,更新控件,并且根据我在数据绑定场景中的理解,UI不应该知道数据来自哪里…你可以认为的背景线程作为将数据推送到UI的东西,所以我不知道backgroundworker是否是我正在搜索的选项.
编辑:
另一个问题来到我的脑海:
您希望在数据/业务对象中的操作期间获得一些UI响应(例如,在重新计算期间设置背景).在绑定到背景的状态属性上增加一个propertychanged是不够的,因为在计算结束后控件被重新绘制是不够的?我的想法是钩住propertychanged事件并调用.update()在控件上…
有什么其他想法吗?
解决方法@H_403_30@
这是一个困难的问题,因为大多数“解决方案”导致大量的自定义代码和大量的调用BeginInvoke()或System.ComponentModel.BackgroundWorker(它本身只是一个薄的封装在BeginInvoke上).
过去,我也发现您很快希望延迟发送INotifyPropertyChanged事件,直到数据稳定.处理一个改变事件的代码通常需要阅读其他特性.当许多属性之一的状态发生变化时,您也经常有一个需要重新绘制的控件,而且您也不需要太多频繁地重新绘制控件.
首先,每个自定义WinForms控件都应该读取所有需要在PropertyChanged事件处理程序中绘制的数据,因此当它是一个WM_PAINT(OnPaint)消息时,它不需要锁定任何数据对象.控制器在获取新数据时不应立即重绘;而应该调用Control.Invalidate(). Windows会将WM_PAINT消息组合到尽可能少的请求中,并且只有当UI线程没有其他任何事情时才发送它们.这样可以最大限度地减少重绘次数和数据对象被锁定的时间. (标准控件大多是通过数据绑定来实现的)
数据对象需要记录改变的内容,然后一旦完成了一组更改,“踢”UI线程调用SendChangeEvents方法,然后调用PropertyChanged事件处理程序(在UI线程上)所有属性已更改. SendChangeEvents()方法正在运行时,必须锁定数据对象以阻止后台线程进行更新.
每当一组更新从数据库读取bean时,UI线程可以通过对BeginInvoke的调用“踢”.通常最好使用定时器进行UI线程轮询,因为Windows在UI消息队列为空时才发送WM_TIMER消息,因此导致UI感觉更加敏感.
还要考虑到根本不使用数据绑定,并且每当定时器触发时,UI都要求每个数据对象“发生什么变化”.数据绑定总是看起来不错,但可以很快成为问题的一部分,而不是部分解决方案.
因为数据对象的锁定/解锁是一种痛苦,并且可能不允许从数据库中读取更新的速度足够快,您可能希望将UI线程传递给数据对象的(虚拟)副本.使数据对象持久/不可变,以便对数据对象的任何更改返回一个新的数据对象,而不是更改当前数据对象可以启用此功能.
持久的对象听起来很慢,但不一定要看一些指针this和that.另请参阅堆栈溢出上的this和that.
还可以看看retlang – Message-based concurrency in .NET.它的消息批处理可能很有用.
(对于WPF,我将有一个View-Model,它设置在UI线程中,然后通过后台线程从多线程模型的“批处理”中更新,然而WPF在组合数据绑定事件WinForms .)
过去,我也发现您很快希望延迟发送INotifyPropertyChanged事件,直到数据稳定.处理一个改变事件的代码通常需要阅读其他特性.当许多属性之一的状态发生变化时,您也经常有一个需要重新绘制的控件,而且您也不需要太多频繁地重新绘制控件.
首先,每个自定义WinForms控件都应该读取所有需要在PropertyChanged事件处理程序中绘制的数据,因此当它是一个WM_PAINT(OnPaint)消息时,它不需要锁定任何数据对象.控制器在获取新数据时不应立即重绘;而应该调用Control.Invalidate(). Windows会将WM_PAINT消息组合到尽可能少的请求中,并且只有当UI线程没有其他任何事情时才发送它们.这样可以最大限度地减少重绘次数和数据对象被锁定的时间. (标准控件大多是通过数据绑定来实现的)
数据对象需要记录改变的内容,然后一旦完成了一组更改,“踢”UI线程调用SendChangeEvents方法,然后调用PropertyChanged事件处理程序(在UI线程上)所有属性已更改. SendChangeEvents()方法正在运行时,必须锁定数据对象以阻止后台线程进行更新.
每当一组更新从数据库读取bean时,UI线程可以通过对BeginInvoke的调用“踢”.通常最好使用定时器进行UI线程轮询,因为Windows在UI消息队列为空时才发送WM_TIMER消息,因此导致UI感觉更加敏感.
还要考虑到根本不使用数据绑定,并且每当定时器触发时,UI都要求每个数据对象“发生什么变化”.数据绑定总是看起来不错,但可以很快成为问题的一部分,而不是部分解决方案.
因为数据对象的锁定/解锁是一种痛苦,并且可能不允许从数据库中读取更新的速度足够快,您可能希望将UI线程传递给数据对象的(虚拟)副本.使数据对象持久/不可变,以便对数据对象的任何更改返回一个新的数据对象,而不是更改当前数据对象可以启用此功能.
持久的对象听起来很慢,但不一定要看一些指针this和that.另请参阅堆栈溢出上的this和that.
还可以看看retlang – Message-based concurrency in .NET.它的消息批处理可能很有用.
(对于WPF,我将有一个View-Model,它设置在UI线程中,然后通过后台线程从多线程模型的“批处理”中更新,然而WPF在组合数据绑定事件WinForms .)