Receiving CrossThreadMessagingException while Debugging WinForms Application - c#

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.

Related

Different InvalidOperationException behavior between debug and runtime

I have the following code in WinForm application with one button and one label:
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => label1.Text = Thread.CurrentThread.ManagedThreadId.ToString());
}
When I started program by VS debugger, the label1.Text = ... will throw a System.InvalidOperationException due to accessing control in working thread. That is no problem.
But if I directly run the exe, I will see the working thread id be shown on label and no exception.
What cause this difference?
update:
If I start it in VS with release mode, there is no exception neither no thread id. So that here is the third result.
Simply: in release mode it isn't managing to detect your broken code as reliably. But: the code is still just as broken either way. You should not attempt to touch UI controls from worker threads, so: don't do that! Are you sure you didn't disable Control.CheckForIllegalCrossThreadCalls somewhere? (note: you should not disable it; I'm just asking if perhaps you have)

Make main thread execute code on button press after form.show

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.

WPF threads and tasks on textchanged event

Using Visual Studio 2012 ulti, C# .NET WPF.
Using Tasks in my code on winforms used to be simple.
All I would do is create a delegate, create a function for my code, create a task and the event would be a simple button. Easy stuff. Problem I have is the following...
Create a thread as per-usual But the event will be on text changed.
The problem im having is thinking about the logic, if I simply change the event I cant see this working as the user could type faster than the code could run ( in this case an sql query select statement). There for it would try to run many tasks which I don't even think would work.
Basically User enters text box that used for searching an account by name or number.
In this textbox I would like to thread the entire process.
The only solution I can think of is as the text changes if there is a thread still running stop that thread and create the new one, but not sure if thats a clean way of doing it as its a sql stored procedure ill be calling.
So any body got a solution to this?
If you need any more info just ask. Ill also provide some code that currently works to give you an understanding if needed...
Set Invoke method up:
private void SetDataGrid(bool AutoGenerateColumns, Object DataSource, String DataMember, DataGridViewAutoSizeColumnsMode Mode)
{
if (this.ParetoGrid.InvokeRequired)
{
this.ParetoGrid.Invoke(new Action<bool, Object, String, DataGridViewAutoSizeColumnsMode>(SetDataGrid),
AutoGenerateColumns, DataSource, DataMember, Mode);
}
else
{
this.ParetoGrid.AutoGenerateColumns = AutoGenerateColumns;
this.ParetoGrid.DataSource = DataSource;
this.ParetoGrid.DataMember = DataMember;
ParetoGrid.AutoResizeColumns(Mode);
}
}
Call invoke method in another method:
Private void GetSomething()
{
//sql code get data
SetDataGrid(true, dataSet1, "Pareto", DataGridViewAutoSizeColumnsMode.AllCells);
}
Then simply start task on event:
private void myButton_Click(Object sender, EventArgs e)
{
Task t = new Task(() => getSomething());
t.Start();
}
As you can see simple stuff, but simple changing event seems to mess the whole logic up.
I'd recomend moving this logic from the task into a Timer callback, then have your OnTextChanged handler actually reset the timer each time it's fired (only have the timer fire once of course). By making the timer elapse after .5-1 sec, or something like that, you'll wait until all of their text has been entered before actually calling your logic. But the user's experience will still be quite responsive.
Example:
private System.Threading.Timer keyEntryTimer = new Timer(Logic,null,-1,-1);
public void HandleEvent(objet sender, EventArgs args)
{
keyEntryTimer.Change(500,-1);
}
public void Logic(objet state)
{
//Your task logic would go here to read from the text etc...
//You'll have to handle any UI updates either by firing off a task once the DB results return or using a dispatcher
}
You can simply cache all accounts when they enter this search mode. Then you can search through cached accounts when they enter text into the textbox. Doing a query in a different thread for every keypress is very heavy on the app.
I would probably do a combination of the other suggested answers and try to delay the firing of the SQL statement using a timer or some similar method, but if the user delayed long enough for the SQL to fire then try to just filter the returned results from that point forward (only if the search string is becoming more restrictive obviously). This could save you expensive SQL round trips and give you a working cache after the first hit (which should be smaller than if you tried to cache everything).
Hope this helps.

Cross-thread: Invoke before the dialog shown

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.

Windows Forms GUI hangs when calling OpenFileDialog.ShowDialog()

my project a three tier architecture project talking to a WCF service in the backend. When the backend is able to fetch data from the service, it notifies the business layer using publish-subscribe, which in return notifies the GUI layer.
I have added an OpenFileDialog to my UI design using Visual Studios designer. A button event handler calls the ShowDialog message. However, once I click the button, the whole UI hangs.
Having googled around a bit, I found out that using delegates is the preferred way to handle tasks like this. However, with nor without delegate the problem persists.
Currently my code looks like this:
private void bOpen_Click(object sender, EventArgs e)
{
Func<Image> del = delegate
{
OpenFileDialog d = new OpenFileDialog();
if (d.ShowDialog() == DialogResult.OK)
{
return Image.FromFile(d.FileName);
}
return null;
};
Invoke(del);
}
I'm coming from the Java world, so I'm not really familiar with the intricacies of C# UI programming.
Anything I'm missing here?
openFileDialog1->ShowHelp = true;
I put this line in my code then the problem was solved.
I seem to have solved the problem adding the [STAThread] Attribute to the main method. I was told to do so once I ran the program in a debugger - which I hadn't done before because I ran the service from Visual Studio and the client regularly from Windows.
[STAThread]
public static void Main(string[] args)
{
GUI gui = new GUI();
gui.ShowDialog();
}
Can anybody explain what exactly is going on though
This tends to be an environmental problem, when you use OpenFileDialog a lot of shell extensions get loaded into your process. A misbehaving one can easily screw up your program. There are a lot of bad ones out there.
Debugging this is difficult, you need an unmanaged debugger since these shell extensions are unmanaged code. You might be able to tell something from the call stack when you break in after the deadlock. Windows debugging symbols required, enable the Microsoft symbol server. But the most effective approach is to use SysInternals' AutoRuns utility. Start by disabling all of the shell extensions that were not produced by Microsoft. Then start re-enabling the ones you cannot live without one by one.
And, as you found out, these shell extension expect to run on an STA thread and fail miserably when they don't get it. The UI thread of a program must always be STA, also to support the clipboard and drag-and-drop and various kinds of controls like WebBrowser. Normally always taken care of automatically by the [STAThread] attribute on the Main() method, put there by the project template. And the Application.Run() call, required to implement the STA contract. Deadlock when you don't.
I believe the "delegate" prefered way actually refers to using a separate thread.
I'm gonna give you an example using BackgroundWorker.
It would look like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
m_Worker.DoWork += new DoWorkEventHandler(m_Worker_DoWork);
m_Worker.ProgressChanged += new ProgressChangedEventHandler(m_Worker_ProgressChanged);
m_Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_Worker_RunWorkerCompleted);
}
void m_Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//Usually, used to update a progress bar
}
void m_Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Usually, used to add some code to notify the user that the job is done.
}
void m_Worker_DoWork(object sender, DoWorkEventArgs e)
{
//e.Argument.ToString() contains the path to the file
//Do what you want with the file returned.
}
private void bOpen_Click(object sender, EventArgs e)
{
OpenFileDialog d = new OpenFileDialog();
if (d.ShowDialog() == DialogResult.OK)
{
m_Worker.RunWorkerAsync(d.FileName);
}
}
BackgroundWorker m_Worker = new BackgroundWorker();
}
Now, as for the reason your UI "hangs", it's because by default, your operation runs on the UI thread, so if you run something heavy the UI won't respond.
I also met this problem. And I tried all the solution here and none can solve it. Then I change the target framework from .Net Framework 4.7 to 4.6.2, the problem solved...
I think my problem is different, as none of the above solutions worked for me.
I wrote temporary code to set the OpenFileDialog.FileName property to something not null or empty string (it was empty string when the hang up occured), and I restarted my computer. When I started up Visual Studio again, and ran it, it worked again without hanging up.

Categories

Resources