INotifyPropertyChanged和线程
我有一个实现INotifyPropertyChanged
的基类:
protected void OnNotifyChanged(string pName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(pName)); } } public event PropertyChangedEventHandler PropertyChanged;
我有一个带有Latitude
属性的派生类,如下所示:
private double latitude; public double Latitude { get { return latitude; } set { latitude = value; OnNotifyChanged("Latitude"); } }
我的派生类也有一个方法Fly
来操纵Latitude
。
我还有一个Form,其TextBox绑定到我的派生类的Latitude
:
txtLat.DataBindings.Clear(); txtLat.DataBindings.Add("Text", bindSrc, "Latitude");
一个线程用于启动Fly
如下所示:
Thread tFly = new Thread(f.Fly); tFly.IsBackground = true; tFly.Start();
当Latitude
更改时,会抛出exception:
DataBinding cannot find a row in the list that is suitable for all bindings.
这似乎是线程亲和力的一个奇怪问题。 最终,代码试图从非UI线程进行更新 – 我不清楚为什么它不仅仅是显示跨线程exception – 我不知道这是否实际上是一个包罗万象的exception处理程序。 如果我删除BindingSource
(并直接绑定到有效的对象),你会得到一个跨线程exception(我预期)。
就个人而言 ,我倾向于手动处理这个问题,即使用一种方法订阅事件,该方法对UI线程进行Invoke
并手动更新Text
。 但是,我只是检查一些以前的跨线程绑定代码是否有帮助……
这是使用Invoke
的示例:
using System; using System.ComponentModel; using System.Threading; using System.Windows.Forms; class FlightUav : INotifyPropertyChanged { protected void OnNotifyChanged(string pName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(pName)); } public event PropertyChangedEventHandler PropertyChanged; private double _latitude; public double Latitude { get { return _latitude; } set { _latitude = value; OnNotifyChanged("Latitude"); } } public void Fly() { for (int i = 0; i < 100; i++) { Latitude++; Thread.Sleep(10); } } [STAThread] static void Main() { using (Form form = new Form()) { FlightUav currentlyControlledFlightUav = new FlightUav(); currentlyControlledFlightUav.PropertyChanged += delegate { // this should be in a *regular* method so that you can -= it when changing bindings... form.Invoke((MethodInvoker)delegate { form.Text = currentlyControlledFlightUav.Latitude.ToString(); }); }; using (Button btn = new Button()) { btn.Text = "Fly"; btn.Click += delegate { Thread tFly = new Thread(currentlyControlledFlightUav.Fly); tFly.IsBackground = true; tFly.Start(); }; form.Controls.Add(btn); Application.Run(form); } } } }
以下是使用我的一些旧线程代码的(修改)版本的示例:
using System; using System.ComponentModel; using System.Threading; using System.Windows.Forms; class FlightUav : INotifyPropertyChanged { protected void OnNotifyChanged(string pName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(pName)); } public event PropertyChangedEventHandler PropertyChanged; private double _latitude; public double Latitude { get { return _latitude; } set { _latitude = value; OnNotifyChanged("Latitude"); } } public void Fly() { for (int i = 0; i < 100; i++) { Latitude++; Thread.Sleep(10); } } [STAThread] static void Main() { using (Form form = new Form()) { FlightUav currentlyControlledFlightUav = new FlightUav(); BindingSource bindSrc = new BindingSource(); var list = new ThreadedBindingList(); list.Add(currentlyControlledFlightUav); bindSrc.DataSource = list; form.DataBindings.Clear(); form.DataBindings.Add("Text", list, "Latitude"); using (Button btn = new Button()) { btn.Text = "Fly"; btn.Click += delegate { Thread tFly = new Thread(currentlyControlledFlightUav.Fly); tFly.IsBackground = true; tFly.Start(); }; form.Controls.Add(btn); Application.Run(form); } } } } public class ThreadedBindingList : BindingList { private readonly SynchronizationContext ctx; public ThreadedBindingList() { ctx = SynchronizationContext.Current; } protected override void OnAddingNew(AddingNewEventArgs e) { SynchronizationContext ctx = SynchronizationContext.Current; if (ctx == null) { BaseAddingNew(e); } else { ctx.Send(delegate { BaseAddingNew(e); }, null); } } void BaseAddingNew(AddingNewEventArgs e) { base.OnAddingNew(e); } protected override void OnListChanged(ListChangedEventArgs e) { if (ctx == null) { BaseListChanged(e); } else { ctx.Send(delegate { BaseListChanged(e); }, null); } } void BaseListChanged(ListChangedEventArgs e) { base.OnListChanged(e); } }
- 从日本IME获取更多数据
- 为什么generics类型的名称在.NET堆栈跟踪中被破坏?
- 获得“元组元素名称的推断。 请使用语言版本7.1或更高版本通过其推断名称访问元素。“
- 使用SignedXml类添加基于Id属性的引用时出现“格式错误的引用元素”
- 在Ado.net C中动态构建Where子句#
- 在ObservableCollection上实现AddRange,并对DataBinding提供适当的支持
- 用于签署Flickr API请求的无效签名(在控制台中进行模拟)
- ADO .NET与SQL Server Management Studio – ADO表现更差
- 当路径太长时,File.Exists()错误地返回false