Probably I don't understand correctly this topic. Here is an issue...
C# Windows Application (.NET 2.0). The MainForm has a button "Query". When the user pushes it, the following should happen:
private void btnQuery_Click(object sender, EventArgs e)
{
querier = new Querier();
OutputForm outputForm = new OutputForm();
querier.ProcessAll(outputForm.OutputReceived);
outputForm.ShowDialog();
}
Querier is the worker. It creates a background thread and runs it to do stuff. The OutputForm is a simple form with txtOutput multiline text-box that should display the output of the working thread.
To allow the working thread send its output, querier.ProcessAll() method receives a callback handler. This is its implementation:
public void OutputReceived(string message)
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate() { this.OutputReceived(message); });
else if (!string.IsNullOrEmpty(message))
txtOutput.AppendText(message + Environment.NewLine);
}
So basically the working thread runs and sends output using the OutputReceived() method, which uses Invoke(), because the working thread can't access the txtOutput field directly.
Note that outputForm.ShowDialog() is called AFTER querier.ProcessAll(). That's because ShowDialog() is blocking.
But here is the problem. If the working thread sends any output BEFORE the dialog is actually shown, I get the exception about cross-thread operation! When I debug it, I see that for some reason this.InvokeRequired() in the OutputReceived() method returns "false"! That's why the working thread tries to access txtOutput directly and crashes.
The problem is clearly about the race condition between the thread and ShowDialog(). If I add Thread.Sleep() in the beginning of the working thread, the dialog shows up and then everything works fine.
Can you explain such behavior?
The best thing to do here would be to ensure that the long running task doesn't actually start until the other form is first displayed. This isn't all that hard thanks to the Shown event in Form.
private void btnQuery_Click(object sender, EventArgs e)
{
querier = new Querier();
OutputForm outputForm = new OutputForm();
outputForm.Shown += delegate { querier.ProcessAll(outputForm.OutputReceived); };
outputForm.ShowDialog();
}
Sorry, I found the answer!
There is one special case when InvokeRequired() will return "false". It's when the control's handle hasn't been created yet. In this case it is forbidden to call Invoke() - so the InvokeRequired() tries to protect you, sort of.
Now I call CreateHandle() method in the CTOR of OutputForm. In this way the handle is created even before the dialog is shown, so InvokeRequired() works as expected.
Related
I have a piece of code that does some calculations and then calls the form.show command. Now I have a library (the revit api) that does not allow me to store variables in a project without being in the main thread.
The logical solution for this is to get the spawned thread to call the main thread using say a producer/consumer pattern with code looking a bit like this:
form.Show(owner);
while(AppIsRunning){
if(clicked)
commit();
else
Thread.sleep(100);
}
However when I do this the gui does not load fully (black background, no text in buttons ext.).
I have also tried doing this using the evoke method
private void BtnOK_Click(object sender, System.EventArgs e)
{
Commit();
Invoke(Commit);
}
private void Invoke(Action commit)
{
commit.Invoke();
}
However this just tells me that it's not the main thread that's executing the commit function.
Is there another way to do this or am I just making an error.
Just to be clear I have a form.show(owner) command that throws an error if it's not executed by the main thread. I also have a commit() function that must be excused by the main thread or it throws an error. The execution must wait until a button press. But the main thread polling the gui thread for changing causes the program to hang. According to my google search it' s also possible to do something involving an external event to get back into the right context but the example given was using python to invoke c# code, is there a good way to raise an external event to get back into a given thread in c#?
Edit: based on some suggestions I have created the following code:
public class ThreadManager
{
static List<ThreadAble> orders = new List<ThreadAble>();
public static bool running = false;
public static void execute(ThreadAble action)
{
orders.Add(action);
}
static System.Timers.Timer timer;
public static void RegisterAPIThreadAndHold(ExternalCommandData commandData)
{
UIApplication uiapp = commandData.Application;
uiapp.Idling += Application_Idle;
}
private static void Application_Idle(Object o,IdlingEventArgs e)
{
if (orders.Count != 0)
{
ThreadAble f = orders.First();
orders.Remove(f);
f.execute();
}
}
}
public interface ThreadAble {
void execute();
}
However this does not appear to actually run when I use it as
public override Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
Form frm = new OverviewForm(ExternalCommandData commandData);
frm.show()
ThreadManager.RegisterAPIThreadAndHold(commandData);
ThreadManager.Execute(new run_ThrowError())
where ThrowError.execute() is
Throw new Exception(" this is actually being executed" );
Your first example could work if you will replace Thread.Sleep by the System.Windows.Forms.Application.DoEvents(). It should give time to paint GUI and do not froze application completly.
form.Show(owner);
while(AppIsRunning){
if(clicked)
commit();
else
{
System.Windows.Forms.Application.DoEvents();
// Thread.sleep(100);
}
}
But this is not perfect solution to achieve this.
Better would be calling Dispatcher.Invoke command inside your dialog to perform MainThread operations.
You can use i.e. GalaSoft library - please refer to DispatcherHelper object documentation and samples.
The two ways to do this I'm aware of are with the External Event or the Idling event.
With the idling event, you'll register it, and while it is registered, your code (in the main thread) will get a callback from Revit every time that it's not busy with something else. Often a few times per second.
Once you are in the Idling callback, then you're able to create transactions and interact with the model. So your callback checks the state of the form and decides whether there is something to do.
The External Event works similarly in terms of registration, but you're able to request a trigger of the callback.
Jeremy Tammik must have 20 posts on thebuildingcoder.typepad.com on Modeless dialog / Revit stuff.
For a simple solution to this, please refer to the Revit SDK ModelessDialog ModelessForm_ExternalEvent sample application. It demonstrates exactly what you are asking for.
In .NET, Windows Forms have an event that fires before the Form is loaded (Form.Load), but there is no corresponding event that is fired AFTER the form has loaded. I would like to execute some logic after the form has loaded.
Can anyone advise on a solution?
You could use the "Shown" event: MSDN - Form.Shown
"The Shown event is only raised the first time a form is displayed; subsequently minimizing, maximizing, restoring, hiding, showing, or invalidating and repainting will not raise this event."
I sometimes use (in Load)
this.BeginInvoke((MethodInvoker) delegate {
// some code
});
or
this.BeginInvoke((MethodInvoker) this.SomeMethod);
(change "this" to your form variable if you are handling the event on an instance other than "this").
This pushes the invoke onto the windows-forms loop, so it gets processed when the form is processing the message queue.
[updated on request]
The Control.Invoke/Control.BeginInvoke methods are intended for use with threading, and are a mechanism to push work onto the UI thread. Normally this is used by worker threads etc. Control.Invoke does a synchronous call, where-as Control.BeginInvoke does an asynchronous call.
Normally, these would be used as:
SomeCodeOrEventHandlerOnAWorkerThread()
{
// this code running on a worker thread...
string newText = ExpensiveMethod(); // perhaps a DB/web call
// now ask the UI thread to update itself
this.Invoke((MethodInvoker) delegate {
// this code runs on the UI thread!
this.Text = newText;
});
}
It does this by pushing a message onto the windows message queue; the UI thread (at some point) de-queues the message, processes the delegate, and signals the worker that it completed... so far so good ;-p
OK; so what happens if we use Control.Invoke / Control.BeginInvoke on the UI thread? It copes... if you call Control.Invoke, it is sensible enough to know that blocking on the message queue would cause an immediate deadlock - so if you are already on the UI thread it simply runs the code immediately... so that doesn't help us...
But Control.BeginInvoke works differently: it always pushes work onto the queue, even it we are already on the UI thread. This makes a really simply way of saying "in a moment", but without the inconvenience of timers etc (which would still have to do the same thing anyway!).
First time it WILL NOT start "AfterLoading",
It will just register it to start NEXT Load.
private void Main_Load(object sender, System.EventArgs e)
{
//Register it to Start in Load
//Starting from the Next time.
this.Activated += AfterLoading;
}
private void AfterLoading(object sender, EventArgs e)
{
this.Activated -= AfterLoading;
//Write your code here.
}
I had the same problem, and solved it as follows:
Actually I want to show Message and close it automatically after 2 second. For that I had to generate (dynamically) simple form and one label showing message, stop message for 1500 ms so user read it. And Close dynamically created form. Shown event occur After load event. So code is
Form MessageForm = new Form();
MessageForm.Shown += (s, e1) => {
Thread t = new Thread(() => Thread.Sleep(1500));
t.Start();
t.Join();
MessageForm.Close();
};
You could also try putting your code in the Activated event of the form, if you want it to occur, just when the form is activated. You would need to put in a boolean "has executed" check though if it is only supposed to run on the first activation.
Here are some details added to previous correct answers, especially the one by Matthias Schippling.
Add an event handler in Form1_Load, like this:
private void Form1_Load(object sender, EventArgs e)
{
this.Shown += new EventHandler(Form1_Shown);
}
Next, add the method that will do something with the code
private void Form1_Shown(Object sender, EventArgs e)
{
draw_on_my_form_or_some_other_action();
}
This an old question and depends more upon when you need to start your routines. Since no one wants a null reference exception it is always best to check for null first then use as needed; that alone may save you a lot of grief.
The most common reason for this type of question is when a container or custom control type attempts to access properties initialized outside of a custom class where those properties have not yet been initialized thus potentially causing null values to populate and can even cause a null reference exceptions on object types. It means your class is running before it is fully initialized - before you have finished setting your properties etc. Another possible reason for this type of question is when to perform custom graphics.
To best answer the question about when to start executing code following the form load event is to monitor the WM_Paint message or hook directly in to the paint event itself. Why? The paint event only fires when all modules have fully loaded with respect to your form load event. Note: This.visible == true is not always true when it is set true so it is not used at all for this purpose except to hide a form.
The following is a complete example of how to start executing you code following the form load event. It is recommended that you do not unnecessarily tie up the paint message loop so we'll create an event that will start executing your code outside that loop.
using System.Windows.Forms;
namespace MyProgramStartingPlaceExample
{
/// <summary>
/// Main UI form object
/// </summary>
public class Form1 : Form
{
/// <summary>
/// Main form load event handler
/// </summary>
public Form1()
{
// Initialize ONLY. Setup your controls and form parameters here. Custom controls should wait for "FormReady" before starting up too.
this.Text = "My Program title before form loaded";
// Size need to see text. lol
this.Width = 420;
// Setup the sub or fucntion that will handle your "start up" routine
this.StartUpEvent += StartUPRoutine;
// Optional: Custom control simulation startup sequence:
// Define your class or control in variable. ie. var MyControlClass new CustomControl;
// Setup your parameters only. ie. CustomControl.size = new size(420, 966); Do not validate during initialization wait until "FormReady" is set to avoid possible null values etc.
// Inside your control or class have a property and assign it as bool FormReady - do not validate anything until it is true and you'll be good!
}
/// <summary>
/// The main entry point for the application which sets security permissions when set.
/// </summary>
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
#region "WM_Paint event hooking with StartUpEvent"
//
// Create a delegate for our "StartUpEvent"
public delegate void StartUpHandler();
//
// Create our event handle "StartUpEvent"
public event StartUpHandler StartUpEvent;
//
// Our FormReady will only be set once just he way we intendded
// Since it is a global variable we can poll it else where as well to determine if we should begin code execution !!
bool FormReady;
//
// The WM_Paint message handler: Used mostly to paint nice things to controls and screen
protected override void OnPaint(PaintEventArgs e)
{
// Check if Form is ready for our code ?
if (FormReady == false) // Place a break point here to see the initialized version of the title on the form window
{
// We only want this to occur once for our purpose here.
FormReady = true;
//
// Fire the start up event which then will call our "StartUPRoutine" below.
StartUpEvent();
}
//
// Always call base methods unless overriding the entire fucntion
base.OnPaint(e);
}
#endregion
#region "Your StartUp event Entry point"
//
// Begin executuing your code here to validate properties etc. and to run your program. Enjoy!
// Entry point is just following the very first WM_Paint message - an ideal starting place following form load
void StartUPRoutine()
{
// Replace the initialized text with the following
this.Text = "Your Code has executed after the form's load event";
//
// Anyway this is the momment when the form is fully loaded and ready to go - you can also use these methods for your classes to synchronize excecution using easy modifications yet here is a good starting point.
// Option: Set FormReady to your controls manulaly ie. CustomControl.FormReady = true; or subscribe to the StartUpEvent event inside your class and use that as your entry point for validating and unleashing its code.
//
// Many options: The rest is up to you!
}
#endregion
}
}
I know this is an old post. But here is how I have done it:
public Form1(string myFile)
{
InitializeComponent();
this.Show();
if (myFile != null)
{
OpenFile(myFile);
}
}
private void OpenFile(string myFile = null)
{
MessageBox.Show(myFile);
}
You can close your form after some execution..
//YourForm.ActiveForm.Close();
LoadingForm.ActiveForm.Close();
First, the apology: I'm new to posting questions on this site, so I apologize for formatting or information errors.I have seen many answers to taking data from a serial port dropped on a form and using it to populate text boxes, graphs, etc. on the main form, using "Invoke" because the serial port is running in a different thread.
I am trying to "generalize" some comm stuff we use all the time in to a class (yes, the old VB6 programmer is trying to grow up :-) and I'm having issues. I can do some things if I force a form name in the main program.cs and use the same namespace for the class, but this sorta defeats the purpose. I've also tried adding an event on the "received" even of the serial port in the class to raise an event on the main form. The event tries to get raised but a cross thread exception occurs.
The code at this point is quite large, so I'll try to "outline" it. In simplistic form, assuming I have a for called "Form1" which contains a text box called textbox1 and a class called "SerialThing":
Form1:
SerialThing mySerialThing ;
Form1_Load:
mySerialThing = new SerialThing();
DisplayData()
Textbox1.Text = "You Got Data!";
SerialThing:
Static SerialPort myDevice;
Init()
myDevice = new SerialPort;
myDevice.DataReceived += new SerialDataReceivedEventHandler(devicePort_DataReceived);
devicePort_DataReceived()
this.Invoke(new EventHandler(DisplayData));
The above will work if the serial port is placed on the main form, but not if created inside the class.
Again, sorry if too complex, or too simplistic. I am looking for an "easy" way to do this, but keep the class "generalized" (ideally not have to have the workspace names match, etc).
-Vin
There are many, many ways to do this. I'll present the classic approach using a custom event, delegates, and Invoke(), as I think it's important to understand that process. Once you've got this down, you can jump to some of the newer approaches.
First, in your SerialThing() class, you declare a Custom event to pass out data when it is received:
class SerialThing
{
public delegate void DataReceivedDelegate(string data);
public event DataReceivedDelegate DataReceived;
static SerialPort myDevice;
public SerialThing()
{
myDevice = new SerialPort();
myDevice.DataReceived += new SerialDataReceivedEventHandler(myDevice_DataReceived);
}
void myDevice_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// ... grab the data and place into a string called "data" ...
string data = "";
// raise our custom event:
if (DataReceived != null)
{
DataReceived(data);
}
}
}
Now, over in Form1, you subscribe to that custom event when you create the instance of SerialThing. Additionally, when that event is received, you marshal the call from the secondary thread to the main thread using InvokeRequired, Invoke, and a delegate:
public partial class Form1 : Form
{
SerialThing mySerialThing;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += new SerialThing.DataReceivedDelegate(mySerialThing_DataReceived);
}
private delegate void DataReceivedDelegate(string data);
void mySerialThing_DataReceived(string data)
{
if (this.InvokeRequired)
{
this.Invoke(new DataReceivedDelegate(mySerialThing_DataReceived), new Object[] { data });
}
else
{
textBox1.Text = data;
}
}
}
EDIT: In response to your comments below...
Think of a delegate as simply a "pointer to a method". When you execute the delegate, the associated method gets run.
The InvokeRequired() portion determines if the code is running in a different thread than the one that created the control. In this case, the control is the Form itself (this). If true is returned, then the event was received in a different thread. We then proceed to this.Invoke() line inside the true portion of the If block. Again this refers to the Form. Thus the Form is requesting to Invoke ("run") the passed delegate on the thread that created it (the main UI thread). We create a instance of the delegate that actually points to the same method we are already in resulting in a recursive call. The second parameter is simply an array of Object used to pass the parameters along with the delegate.
When Invoke() is run we end up re-entering the method because of the recursive call. At this point, however, the InvokeRequired() check will return false as we are now running in the main UI thread. Therefore we drop down into the false portion of the If statement where we update the TextBox. In this pattern it is safe to update an GUI controls in the else block of the If statement.
Note that a recursive call isn't necessary here. This is simply a style choice. We could have instead used a second "helper" function that the delegate pointed to, and Invoked that instead. The recursive approach reduces the number of methods required.
This is perhaps the most verbose approach to solving this type of problem. I like it, though, as it shows the flow of events and data, and movement between the threads.
We could shorten all the Form code to just this, using anonymous delegates:
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += delegate (string data)
{
this.Invoke((MethodInvoker)(delegate() { textBox1.Text = data; }));
};
}
I don't know about you, but as a former VB6 programmer myself, that just looks weird when you first see that type of thing.
I've also used components that I know have things running in different
threads, yet the "form code" has never had to use the delegate stuff,
so maybe there's something that can be buried into the class?
Yes, it's possible to bake some "magic" into a class so that it raises events already on the main UI thread, thus not requiring any Invoke() calls. One way to do this is thru using a SynchronizationContext.
Another possibility for approaching this type of problem would be to use a BackgroundWorker() control which has events such as ProgressChanged() and RunWorkerCompleted() that are raised in the main UI thread for you (they do the necessary invoking type stuff under the hood for you).
I have a console app at the moment, which monitors a folder for files, and then based on rules and the file name, copies any new file to a location on the network.
I have a requirement to make the application more pretty, so decided to go with a simple WinForms single form application which displays status and 'last updated file' type information.
The console app was written in such a way that all Console display information went through a single method, which I called 'Notify', taking two parameters. A string to display the information I want the user to see, and an ErrorLevel Enum, which, if 'Normal' displayed in green text, if Warning, was yellow, and if error, was red. But the point is, all my code just did was use the 'Notify' method to output any text.
I want to change my console app into a normal class, run it as a background worker from the WinForms project, and have the Notify method in the thread send updates to the winforms app, safely. I think it can be done with events, but I am not sure what would be the best way to handle this. Could you propose a method to get this working?
There's the 'Invoke' way of doing things. Is it good? Something like:
this.BeginInvoke (new MethodInvoker(() => UpdateLabel(s));
It seems it would be basic, but I'd like to still make use of my Notify method, and have that send messages to the UI layer.
I also need the console app to send messages to the thread. For example, 'Stop', where I then run code that gracefully quits the thread... and also, 'Refresh', which does some logic within the thread.
Another option is to run the processing class as a service? And then have a UI that somehow connects to the system service and gets updates? I have never done anything like that, but the process is meant to run all the time...
At the moment, I have my code running, but no updated to the UI:
public partial class MainForm : Form
{
BackgroundWorker _bw = new BackgroundWorker();
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
_bw.DoWork += bw_DoWork;
_bw.RunWorkerAsync();
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
var bw = sender as BackgroundWorker;
var monitor = new Monitor();
monitor.RunMe();
}
}
I think I just need to find a way to get my Notify method in my thread to send a message or something (An object that I create, with Message String and ErrorCode properties?) back to my UI, and process it safely on the UI.
And here is the code within the class (thread)...
public class Monitor
{
public void RunMe()
{
Notify("Checking for network connectivity...", Constants.ErrorLevel.Information);
if (FileManagement.FolderExists(Constants.FolderToMonitor) == false)
{
Notify("Unable to monitor folder - Aborting.", Constants.ErrorLevel.Error);
Console.ReadKey();
return;
}
Notify("OK", Constants.ErrorLevel.Information);
....
}
Note: Readkey will be removed..
There may be a better approach, but if your Notify method needs to interact with the GUI, try using the ReportProgress event on the BackgroundWorker. You can pas an object as the state parameter, and probably just ignore the progress value.
I am using Wndows XP SP3 x86 + VSTS 2008 to write a simple Windows Forms application using C#. There is a button called button1 and here is the event handler for its click event, when executing the if statement, there is Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException. Does anyone have any good ideas what is wrong?
private void button1_Click(object sender, EventArgs e)
{
string recording = ConfigurationSettings.AppSettings["recording"];
// exception thrown when executing the following if statement
if (recording.Equals("enable", StringComparison.InvariantCultureIgnoreCase))
{
CameraEncoder.Stop();
}
}
Some more code:
static WMEncoder CameraEncoder = new WMEncoder();
EDIT1:
I am confused how to apply Marc's idea of using Invoke in my code. Should I use the following code segment?
CameraEncoder.Invoke((MethodInvoker) delegate
{
CameraEncoder.Stop();
});
Normally, the problem when we see this (regularly) is something like a worker thread or a timer updating the UI - but a button click should be raised through the UI thread, so I don't think it is the "usual problem".
So: what is camera? And what is Recording? Neither is explained, and we can't guess without introducing extra variables...
Depending on what they are, maybe this'll work...
camera.Invoke((MethodInvoker) delegate
{
if (camera.Equals("enable", StringComparison.InvariantCultureIgnoreCase))
{
Recording.Stop();
}
});
But without knowing what canera is, I'm clutching at straws...
Maybe the camera object is created and managed by another thread.. Could you expose more code regarding the camera object?
I know WMEncoder is a COM object. You might try creating CameraEncoder in the GUI thread instead of a different thread.