I have a winform (MyFrm) which contains a winforms user control (myWinformUserControl). I call a public method (MyMethod) from this user control:
using (var frm = new MyFrm())
{
frm.myWinformUserControl.MyMethod();
}
public class myWinformUserControl: System.Windows.Forms.UserControl
{
public void MyMethod()
{
// Do some stuff
TryToDisconnect();
}
private void TryToDisconnect()
{
myComObj.Disconnect(); // This throws COMException
}
}
This user control communicates with a COM object. When I call to disconnect on the COM Object an exception is thrown:
COMException: Cannot call a 'Disconnect()' from within an event
so in order to solve this I use a thread instead of calling it directly:
public void MyMethod()
{
System.Threading.Thread th = new System.Threading.Thread(new
System.Threading.ThreadStart(TryToDisconnect));
th.SetApartmentState(System.Threading.ApartmentState.STA);
th.IsBackground = true;
th.Priority = System.Threading.ThreadPriority.Highest;
th.Start();
}
The below block of code indicated at the beginning of this question:
using (var frm = new MyFrm())
{
frm.myWinformUserControl.MyMethod();
}
... is called from a WPF MVVM view model class.
The problem I have here is that I need MyMethod to be done immediatelly so I set highest priority for the thread, and I want the call in view model class (frm.myWinformUserControl.MyMethod()) to stop and do not continue until this thread is completed. I have observed that the thread is not immediatelly executed, so how can I achieve this?
I have tried an asynchronous call and wait until it is completed instead of using a thread:
public void MyMethod()
{
Action action = Foo;
IAsyncResult result = action.BeginInvoke(ar => action.EndInvoke(ar), null);
result.AsyncWaitHandle.WaitOne();
}
public delegate void Action();
private void Foo()
{
TryToDisconnect();
}
but again the same COMException is thrown:
COMException: Cannot call a 'Disconnect()' from within an event
Also, in case of using the thread, If I immediatelly do th.Join() just after doing th.start() it does not work.
I am trying to preload server form in the constructor of client form, in a separate thread. My reason is that server load is time consuming.
Here's the client form, you can see in the constructor that I am calling Preload(). There's also a button, clicking on it should show the server, which should be fast since the server form is already preloaded:
public partial class Form1 : Form
{
ServerUser server = null;
public Form1()
{
InitializeComponent();
Preload();
}
public async void Preload()
{
await Task.Run(() =>
{
server = new ServerUser();
server.LoadDocument();
server.ShowDialog();
}
);
}
private void button1_Click(object sender, EventArgs e)
{
server.Show();
}
}
Here I try to preload form ServerUser in constructor of Form1 and if I click on button1 Server form show faster
And here's the server form:
public partial class ServerUser : Form
{
public ServerUser()
{
InitializeComponent();
}
public void LoadDocument()
{
ConfigureSource();
}
public void ConfigureSource()
{
InvokeUpdateControls();
}
public void InvokeUpdateControls()
{
UpdateControls();
}
private void UpdateControls()
{
richTextBox1.Rtf = Resource1.ReferatPPC_Bun___Copy;
}
}
You need to rethink your design. You should create all forms from the main UI thread, and offload the heavy lifting(non UI stuff) to the background threads. Calling UI methods from background threads results in undefined behavior or exceptions.
Also, I think you misunderstand what await does. You call Preload() synchronously even though it is an asynchronous method. This means that by the time server.Show(); is called, Server might still be running one of these methods:
server = new ServerUser(); //you should move this outside of Task.Run()
server.LoadDocument(); //implement this method using background threads
server.ShowDialog(); //this will actually throw an exception if called via Task.Run();
From your sample I suppose LoadDocument is the expensive operation. You should rewrite that method to run on a background thread and make ServerUser show a loading screen untill LoadDocument() completes. Make sure that all UI methods from LoadDocument are called via BeginInvoke
or proper async/await.
Send in constructor;
public partial class ServerUser : Form
{
public ServerUser(Form1 form1)
{
InitializeComponent();
form1.Preload();
}
public void LoadDocument()
{
ConfigureSource();
}
public void ConfigureSource()
{
InvokeUpdateControls();
}
public void InvokeUpdateControls()
{
UpdateControls();
}
private void UpdateControls()
{
richTextBox1.Rtf = Resource1.ReferatPPC_Bun___Copy;
}
}
public partial class Form1 : Form
{
ServerUser server = null;
public Form1()
{
InitializeComponent();
Preload();
}
public async void Preload()
{
await Task.Run(() =>
{
server = new ServerUser();
server.LoadDocument();
server.ShowDialog();
}
);
}
private void button1_Click(object sender, EventArgs e)
{
server=new ServerUser(this);// or whatever you want
server.Show();
}
}
I made a sample Consumer/Producer thread application, so I can learn how to properly use it.
I want it to allow for one thread to send commands to the GUI thread, to update the GUI with content.
I have it working, but there's one small issue. The GUI thread is my consumer thread, so I have it always checking for new commands (using a while loop). The issue is that because of this while loop, the GUI never displays because it's always stuck in the while loop. Note that the string Queue will eventually be replaced with a more complex object (one that holds data & command type).
I'm not sure how else to allow the GUI thread to consume commands without interrupting GUI functionality. Am I doing something wrong?
Here's my Form1.cs code (the form only contains 1 RichTextBox for showing output called OutputBox).
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
namespace MultiThreading
{
class ThreadCommandQueue
{
public static ThreadCommandQueue instance = new ThreadCommandQueue();
private Queue<string> m_queue;
private Object m_lock;
public static ThreadCommandQueue GetInstance()
{
return instance;
}
private ThreadCommandQueue()
{
m_queue = new Queue<string>();
m_lock = new Object();
}
public void Add(
string data_to_add)
{
lock (m_lock)
{
m_queue.Enqueue(data_to_add);
}
}
public string Get()
{
lock (m_lock)
{
if (m_queue.Count > 0)
{
return m_queue.Dequeue();
}
return null;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void PopulateThreadCommandQueue()
{
int i = 0;
while(true)
{
ThreadCommandQueue.GetInstance().Add("Item #: " + i.ToString());
i++;
}
}
private void Form1_Load(object sender, EventArgs e)
{
// Create the Command Queue....
ThreadCommandQueue.GetInstance();
// Create a Testing Producer Thread
Thread ProducerThread = new Thread(PopulateThreadCommandQueue);
ProducerThread.Start();
// The GUI thread is the Consumer, so keep checking the CommandQueue for data...
while(true)
{
string latest = ThreadCommandQueue.GetInstance().Get();
if(latest != null)
{
OutputBox.Text += latest + "\n";
}
}
}
}
}
Use ConcurrentQueue. So no locking is required to add and get from Queue.
Also you in real time you will not receive commands continuously from UI thread (while loop). If you have such scenario use a separate thread to receive outcome.
Then from the receivers thread you can update UI using Invoke command, as below.
//This method called from receiver thread
public void UpdateForm(Data d)
{
if(this.InvokeRequired)
{
this.Invoke(new MethodInvoker(() => this.UpdateFormUI(r)));
}
else
{
this.UpdateFormUI(data)
}
}
public void UpdateFormUI(Data d)
{
//Does actual ui update
}
Okay, the problem here is that you need to poll the message loop all the time to make GUI working and you also need to poll your IPC command queue all the time to make your commands working and you need this polling to happen at the same time on the same thread.
There are multiple ways to resolve this, but the easiest would be to process the message loop and when there is nothing to process, do your IPC command queue processing. For WinForms application this would be something like:
public Form1()
{
InitializeComponent();
Application.Idle += (sender, eargs) => ProcessCommands();
}
private void ProcessCommands()
{
while(true)
{
string latest = ThreadCommandQueue.GetInstance().Get();
if(string.IsNullOrEmpty(latest)) return;
OutputBox.Text += latest + "\n";
}
}
I'm doing async network in C#.NET with the TcpClient and TcpListener classes.
I use WinForms for the GUI.
Whenever I receive data from a remote computer, the operation is done on a different underlying thread.
What I need to do is to update the GUI of my application whenever I receive a network response.
// this method is called whenever data is received
// it's async so it runs on a different thread
private void OnRead(IAsyncResult result)
{
// update the GUI here, which runs on the main thread
// (a direct modification of the GUI would throw a cross-thread GUI exception)
}
How can I achieve that?
In Winforms you need to use Control.Invoke Method (Delegate) to make sure that control is updated in the UI thread.
Example:
public static void PerformInvoke(Control ctrl, Action action)
{
if (ctrl.InvokeRequired)
ctrl.Invoke(action);
else
action();
}
Usage:
PerformInvoke(textBox1, () => { textBox1.Text = "test"; });
in GUI write function like this:
public void f() {
MethodInvoker method = () => {
// body your function
};
if ( InvokeRequired ) {
Invoke( method ); // or BeginInvoke(method) if you want to do this asynchrous
} else {
method();
}
}
if you in other thread call this function it will be calling in GUI thread
I added an extension method to the code suggested by Alex. It gets even better!
// Extension method
public static class GuiHelpers
{
public static void PerformInvoke(this Control control, Action action)
{
if (control.InvokeRequired)
control.Invoke(action);
else
action();
}
}
// Example of usage
private void EnableControls()
{
panelMain.PerformInvoke(delegate { panelMain.Enabled = true; });
linkRegister.PerformInvoke(delegate { linkRegister.Visible = true; });
}
I find that the .NET event model is such that I'll often be raising an event on one thread and listening for it on another thread. I was wondering what the cleanest way to marshal an event from a background thread onto my UI thread is.
Based on the community suggestions, I've used this:
// earlier in the code
mCoolObject.CoolEvent+=
new CoolObjectEventHandler(mCoolObject_CoolEvent);
// then
private void mCoolObject_CoolEvent(object sender, CoolObjectEventArgs args)
{
if (InvokeRequired)
{
CoolObjectEventHandler cb =
new CoolObjectEventHandler(
mCoolObject_CoolEvent);
Invoke(cb, new object[] { sender, args });
return;
}
// do the dirty work of my method here
}
I have some code for this online. It's much nicer than the other suggestions; definitely check it out.
Sample usage:
private void mCoolObject_CoolEvent(object sender, CoolObjectEventArgs args)
{
// You could use "() =>" in place of "delegate"; it's a style choice.
this.Invoke(delegate
{
// Do the dirty work of my method here.
});
}
A couple of observations:
Don't create simple delegates explicitly in code like that unless you're pre-2.0 so you could use:
BeginInvoke(new EventHandler<CoolObjectEventArgs>(mCoolObject_CoolEvent),
sender,
args);
Also you don't need to create and populate the object array because the args parameter is a "params" type so you can just pass in the list.
I would probably favor Invoke over BeginInvoke as the latter will result in the code being called asynchronously which may or may not be what you're after but would make handling subsequent exceptions difficult to propagate without a call to EndInvoke. What would happen is that your app will end up getting a TargetInvocationException instead.
I shun redundant delegate declarations.
private void mCoolObject_CoolEvent(object sender, CoolObjectEventArgs args)
{
if (InvokeRequired)
{
Invoke(new Action<object, CoolObjectEventArgs>(mCoolObject_CoolEvent), sender, args);
return;
}
// do the dirty work of my method here
}
For non-events, you can use the System.Windows.Forms.MethodInvoker delegate or System.Action.
EDIT: Additionally, every event has a corresponding EventHandler delegate so there's no need at all to redeclare one.
I made the following 'universal' cross thread call class for my own purpose, but I think it's worth to share it:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace CrossThreadCalls
{
public static class clsCrossThreadCalls
{
private delegate void SetAnyPropertyCallBack(Control c, string Property, object Value);
public static void SetAnyProperty(Control c, string Property, object Value)
{
if (c.GetType().GetProperty(Property) != null)
{
//The given property exists
if (c.InvokeRequired)
{
SetAnyPropertyCallBack d = new SetAnyPropertyCallBack(SetAnyProperty);
c.BeginInvoke(d, c, Property, Value);
}
else
{
c.GetType().GetProperty(Property).SetValue(c, Value, null);
}
}
}
private delegate void SetTextPropertyCallBack(Control c, string Value);
public static void SetTextProperty(Control c, string Value)
{
if (c.InvokeRequired)
{
SetTextPropertyCallBack d = new SetTextPropertyCallBack(SetTextProperty);
c.BeginInvoke(d, c, Value);
}
else
{
c.Text = Value;
}
}
}
And you can simply use SetAnyProperty() from another thread:
CrossThreadCalls.clsCrossThreadCalls.SetAnyProperty(lb_Speed, "Text", KvaserCanReader.GetSpeed.ToString());
In this example the above KvaserCanReader class runs its own thread and makes a call to set the text property of the lb_Speed label on the main form.
I think the cleanest way is definitely to go the AOP route. Make a few aspects, add the necessary attributes, and you never have to check thread affinity again.
Use the synchronisation context if you want to send a result to the UI thread. I needed to change the thread priority so I changed from using thread pool threads (commented out code) and created a new thread of my own. I was still able to use the synchronisation context to return whether the database cancel succeeded or not.
#region SyncContextCancel
private SynchronizationContext _syncContextCancel;
/// <summary>
/// Gets the synchronization context used for UI-related operations.
/// </summary>
/// <value>The synchronization context.</value>
protected SynchronizationContext SyncContextCancel
{
get { return _syncContextCancel; }
}
#endregion //SyncContextCancel
public void CancelCurrentDbCommand()
{
_syncContextCancel = SynchronizationContext.Current;
//ThreadPool.QueueUserWorkItem(CancelWork, null);
Thread worker = new Thread(new ThreadStart(CancelWork));
worker.Priority = ThreadPriority.Highest;
worker.Start();
}
SQLiteConnection _connection;
private void CancelWork()//object state
{
bool success = false;
try
{
if (_connection != null)
{
log.Debug("call cancel");
_connection.Cancel();
log.Debug("cancel complete");
_connection.Close();
log.Debug("close complete");
success = true;
log.Debug("long running query cancelled" + DateTime.Now.ToLongTimeString());
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
SyncContextCancel.Send(CancelCompleted, new object[] { success });
}
public void CancelCompleted(object state)
{
object[] args = (object[])state;
bool success = (bool)args[0];
if (success)
{
log.Debug("long running query cancelled" + DateTime.Now.ToLongTimeString());
}
}
I've always wondered how costly it is to always assume that invoke is required...
private void OnCoolEvent(CoolObjectEventArgs e)
{
BeginInvoke((o,e) => /*do work here*/,this, e);
}
As an interesting side note, WPF's binding handles marshaling automatically so you can bind the UI to object properties that are modified on background threads without having to do anything special. This has proven to be a great timesaver for me.
In XAML:
<TextBox Text="{Binding Path=Name}"/>
You can try to develop some sort of a generic component that accepts a SynchronizationContext as input and uses it to invoke the events.
I am using something like
Invoke((Action)(() =>
{
//your code
}));