多UI线程与数据绑定问题求助:跨线程UI更新异常
多UI线程场景下的BindingList与UI同步更新问题
场景说明
应用程序为每个窗体启动独立UI线程,以此提升循环更新性能并支持模态弹窗(如选择值后打开窗体)。但单UI线程的SynchronizationContext无法适配该架构,导致UI更新出现问题。
现有实现代码
1. ApplicationContext中多线程启动窗体
public AppContext() { foreach(var form in activeForms) { form.Load += Form_Load; form.FormClosed += Form_FormClosed; StartFormInSeparateThread(form); //form.Show(); } } private void StartFormInSeparateThread(Form form) { Thread thread = new Thread(() => { Application.Run(form); }); thread.ApartmentState = ApartmentState.STA; thread.Start(); }
2. 尝试实现的多UI线程安全BindingList
List<SynchronizationContext> listctx = new(); public ThreadSafeBindingList2() { //SynchronizationContext ctx = SynchronizationContext.Current; //listctx.Add(ctx); } public void SyncContxt() { SynchronizationContext ctx = SynchronizationContext.Current; listctx.Add(ctx); } protected override void OnAddingNew(AddingNewEventArgs e) { for (int i = 0; i < listctx.Count; i++) { if (listctx[i] == null) { BaseAddingNew(e); } else { listctx[i].Send(delegate { BaseAddingNew(e); }, null); } } } void BaseAddingNew(AddingNewEventArgs e) { base.OnAddingNew(e); } protected override void OnListChanged(ListChangedEventArgs e) { for (int i = 0; i < listctx.Count; i++) { if (listctx[i] == null) { BaseListChanged(e); } else { listctx[i].Send(delegate { BaseListChanged(e); }, null); } } } void BaseListChanged(ListChangedEventArgs e) { base.OnListChanged(e); }
3. 静态数据更新中心(含BackgroundWorker)
private static void BackgroundWorker_DoWork(object? sender, DoWorkEventArgs e) { if (timerStart is false) { Thread.Sleep(6000); timerStart = true; } while (DisplayTimerUpdateBGW.CancellationPending is false) { threadSleepTimer = OrderList.Where(x => x.Status != OrderOrderlineStatus.Claimed).ToList().Count > 20 ? 2000 : 1000; if (OrderList.Count > 40) threadSleepTimer = 3000; UpdateDisplayTimer(); Thread.Sleep(threadSleepTimer); } } private static void UpdateDisplayTimer() { var displayLoopStartTimer = DateTime.Now; TimeSpan displayLoopEndTimer = new(); Span<int> orderID = CollectionsMarshal.AsSpan(OrderList.Select(x => x.ID).ToList()); for (int i = 0; i < orderID.Length; i++) { OrderModel order = OrderList[i]; order.OrderInfo = "Ble"; Span<int> OrderLineID = CollectionsMarshal.AsSpan(order.Orderlines.Select(x => x.Id).ToList()); for (int j = 0; j < OrderLineID.Length; j++) { OrderlineModel ol = order.Orderlines[j]; TimeSpan TotalElapsedTime = ol.OrderlineCompletedTimeStamp != null ? (TimeSpan)(ol.OrderlineCompletedTimeStamp - ol.OrderlineReceivedTimeStamp) : DateTime.Now - ol.OrderlineReceivedTimeStamp; string displaytimerValue = ""; if (ol.OrderlineCompletedTimeStamp == null) displaytimerValue = TotalElapsedTime.ToString(@"mm\:ss"); else displaytimerValue = $" {(DateTime.Now - ol.OrderlineCompletedTimeStamp)?.ToString(@"mm\:ss")} \n({TotalElapsedTime.ToString(@"mm\:ss")})"; ol.DisplayTimer = displaytimerValue; } } }
需求
所有窗体的Label和DataGridView均绑定同一BindingList,希望借助INotifyPropertyChanged实现所有UI线程中的属性同步更新,寻求可行解决方案。
内容的提问来源于stack exchange,提问作者Ifirit
相关产品推荐
相关产品推荐

