I'm having issues updating the UI threads. Application is running 1 UI thread for each form, meaning just using SyncronizationContext with the UI thread doesn't work. I'm doing this for looping update performance as well as modal popup possibilities like select value before you can use the form.
How I'm creating it in 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();
}
There are controls on each for that are databound and updating with values from the same databound object. Controls being Labels and DataGridview (bound to a bindinglist). What would be ideal is having the Bindinglist threadsafe and execute on these multiple UI threads. Found some examples that I attempted like this:
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);
}
I'm also using a static class as a data property change hub for all controls so I don't change the databinding source more than once (again due to performance), where I have a background worker "ticking" every 1-3 seconds depending on system load:
private static void BackgroundWorker_DoWork(object? sender, DoWorkEventArgs e)
{
if (timerStart is false)
{
Thread.Sleep(6000);
timerStart = true;
}
while (DisplayTimerUpdateBGW.CancellationPending is false)
{
//UIThread.Post((object stat) => //Send
//{
threadSleepTimer = OrderList.Where(x => x.Status != OrderOrderlineStatus.Claimed).ToList().Count > 20 ? 2000 : 1000;
if (OrderList.Count > 40)
threadSleepTimer = 3000;
UpdateDisplayTimer();
//}, null);
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;
}
}
}
Ideally I want to have the labels and datagridview properties databindings so that I can have INotifyPropertyChanged just updating these relevant properties in all UI threads.
Any help would be appreciated!