|
-
Aug 31st, 2022, 10:03 AM
#1
WinForms, MDI, multithreading - delegate to send events from thread to UI thread
I can't figure out how to send events from a worker thread to the UI thread.
Here's my setup:
I made an app with an MDI main form, which has a few other forms open in it. The MDI creates a new thread that does data synchronization between local database and server database.
I want to send events when the data synchronization is complete for each table (about 50 tables) to each form that subscribes to the events, and each form will then refresh their controls (data grids, drop down menus, etc. that corresponds to the table that finished data synchronization)
In the main MDI form, I have this:
Code:
private cDB_Synchronization DB_Synchronization = new cDB_Synchronization();
public delegate void del_StartSync(int timeout_count);
public static del_StartSync proc_StartSync = null;
// to start the sync thread
proc_StartSync = new del_StartSync(Start_Synchronization);
proc_StartSync.BeginInvoke(3, Sync_Callback, null);
// the sync thread:
private void Start_Synchronization(int timeout_count)
{
this.DB_Synchronization.Sync_Start();
}
// callback when thread finished
public void Sync_Callback(IAsyncResult t)
{
proc_StartSync.EndInvoke(t);
Invoke(new Action(() =>
{
this.tssl_SyncStatus.Text = "Synchronization complete!";
}));
proc_StartSync = null;
}
// when I open the client form, I pass the db sync instance to the new form
HomePage home_page = new HomePage(this.DB_Synchronization);
home_page.Show();
In the HomePage client form:
Code:
private cDB_Synchronization DB_Synchronization = null;
public HomePage(cDB_Synchronization dB_Synchronization)
{
this.DB_Synchronization = dB_Synchronization;
// subscribe to the table sync events
this.DB_Synchronization.TableSyncComplete -= TableSyncComplete;
this.DB_Synchronization.TableSyncComplete += TableSyncComplete;
InitializeComponent();
}
public void TableSyncComplete(cSync_Table tbl)
{
if (tbl.Table_Summary.Total_Actions > 0) // refresh only if there are changes
{
if ((new string[] { "table 1", "table 2" }).Contains(tbl.Table_Name))
{
// refresh data in the grid view, but getting Error :
// 'No row can be added to a DataGridView control that does not have columns. Columns must be added first.'
// columns are there, so I don't get why this error ?
this.submit_search();
// this also does not work, Error:
//'Invoke or BeginInvoke cannot be called on a control until the window handle has been created.'
// window is already open when the event is executed, so I don't get this error either
Invoke(new Action(() =>
{
this.submit_search();
}));
}
}
}
In the cDB_Synchronization - this is running in another thread
Code:
public delegate void del_TableSyncComplete(cSync_Table tbl);
public event del_TableSyncComplete TableSyncComplete;
public void Sync_Start()
{
// send events for each table
// this works, but not sure if correct
this.TableSyncComplete?.Invoke(tbl);
// this also works, not sure which one is correct though,
// or if it has anything to do with the errors I am getting
foreach (Delegate del in this.TableSyncComplete.GetInvocationList())
del.DynamicInvoke(tbl);
}
Please help! I am running out of ideas
Last edited by CVMichael; Aug 31st, 2022 at 10:13 AM.
-
Sep 1st, 2022, 01:21 AM
#2
Re: WinForms, MDI, multithreading - delegate to send events from thread to UI thread
 Originally Posted by CVMichael
I can't figure out how to send events from a worker thread to the UI thread.
That's because there is no such thing. Events are defined like so:
csharp Code:
public event EventHandler SomethingHappended;
protected void OnSomethingHappened(EventArgs e)
{
SomethingHappened?.Invoke(this, e);
}
The OnX method is where the X event is actually raised. When you want to raise that event, you call that method:
csharp Code:
// Do something here.
// Raise the event.
OnSomethingHappened(EventArgs.Empty);
In code that can or will execute on a secondary thread, you can marshal a method call to the UI thread to execute code on the UI thread. That method can do whatever you want. It's just a method. If you want to raise your event in that method, do so, just as I showed above:
csharp Code:
private void RaiseSomethingHappened()
{
OnSomethingHappened(EventArgs.Empty);
}
and:
csharp Code:
Invoke(RaiseSomethingHappened);
Alternatively, you could use a lambda to call the method that raises the event directly:
csharp Code:
Invoke(() => OnSomethingHappened(EventArgs.Empty));
In summary, you "send" a method call to the UI thread, just as you always do, then raise the event in that method, just as you always do.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|