wpf InvalidOperationException when using parameters in constructor [duplicate] - c#

I am using http://www.codeproject.com/KB/IP/Facebook_API.aspx
I am trying to call the XAML which is created using WPF. But it gives me an error:
The calling thread must be STA, because many UI components require this.
I don't know what to do. I am trying to do this:
FacebookApplication.FacebookFriendsList ffl = new FacebookFriendsList();
But it is giving me that error.
I added a background worker:
static BackgroundWorker bw = new BackgroundWorker();
static void Main(string[] args)
{
bw.DoWork += bw_DoWork;
bw.RunWorkerAsync("Message to worker");
Console.ReadLine();
}
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
// This is called on the worker thread
FacebookApplication.FacebookFriendsList ffl = new FacebookFriendsList();
Console.WriteLine(e.Argument); // Writes "Message to worker"
// Perform time-consuming task...
}

Try to invoke your code from the dispatcher:
Application.Current.Dispatcher.Invoke((Action)delegate{
// your code
});

If you make the call from the main thread, you must add the STAThread attribute to the Main method, as stated in the previous answer.
If you use a separate thread, it needs to be in a STA (single-threaded apartment), which is not the case for background worker threads. You have to create the thread yourself, like this:
Thread t = new Thread(ThreadProc);
t.SetApartmentState(ApartmentState.STA);
t.Start();
with ThreadProc being a delegate of type ThreadStart.

You can also try this
// create a thread
Thread newWindowThread = new Thread(new ThreadStart(() =>
{
// create and show the window
FaxImageLoad obj = new FaxImageLoad(destination);
obj.Show();
// start the Dispatcher processing
System.Windows.Threading.Dispatcher.Run();
}));
// set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// make the thread a background thread
newWindowThread.IsBackground = true;
// start the thread
newWindowThread.Start();

I suspect that you are getting a callback to a UI component from a background thread. I recommend that you make that call using a BackgroundWorker as this is UI thread aware.
For the BackgroundWorker, the main program should be marked as [STAThread].

Just mark your program Main method with the [STAThread] attribute and the error goes away! it's magic :)
Example:
class Program {
[STAThread]
static void Main(string[] args) {
// My code here
}
}

In my case, I wanted to launch a WPF window from a console app. Simply setting the Main method with [STAThread] didn't work.
A combination of Timores' and Mohammad's answer worked for me:
private static void StaThreadWrapper(Action action)
{
var t = new Thread(o =>
{
action();
System.Windows.Threading.Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
Example usage:
StaThreadWrapper(() =>
{
var mainWindow = new MainWindow();
mainWindow.Show();
});

For me, this error occurred because of a null parameter being passed. Checking the variable values fixed my issue without having to change the code. I used BackgroundWorker.

If the Application.Current is null for example by unit test, you can try this:
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke( YOUR action )

Another situation if you may meet, choosing which Window to new and show.
Don't make the choice in App.xaml.cs' App() or OnStartup(), instead, make the choice in Startup event.
// App.xaml.cs
private App()
{
Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
window.Show(); // bad 1
}
protected override void OnStartup(StartupEventArgs e)
{
Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
window.Show(); // bad 2
base.OnStartup(e);
}
Below should be good
// App.xaml.cs
private App()
{
Startup += Application_Startup;
}
private void Application_Startup(object sender, StartupEventArgs e)
{
Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
window.Show(); // good
}
Also remember to remove the StartupUri from App.xaml
<!--App.xaml-->
<Application StartupUri="MainWindow">
<!--remove StartupUri-->
</Application>
OR add the event here is OK too.
<!--App.xaml-->
<Application Startup="Application_Startup">
</Application>
// App.xaml.cs
private App()
{
}
private void Application_Startup(object sender, StartupEventArgs e)
{
Window window = CheckSession() ? new InstallWindow() : (Window)new LoginWindow();
window.Show(); // good
}

If you call a new window UI statement in an existing thread, it throws an error. Instead of that create a new thread inside the main thread and write the window UI statement in the new child thread.

Related

Program keeps crashing on "ShowDialog" due to an apparent "MutliThreading" error or Build/Debugging issue [duplicate]

I get the following exception when calling saveFileDialog.ShowDialog() in a background thread:
Current thread must be set to single
thread apartment (STA) mode before OLE
calls can be made. Ensure that your
Main function has STAThreadAttribute
marked on it.
According to this:
To fix the problem, insert the
statement:
Threading.Thread.CurrentThread.ApartmentState = Threading.ApartmentState.STA;
in Main right before the
Application.Run statement.
But the Application.Run statement is in Program.cs which seems to be generated code so any changes might be unexpectedly lost. Also, I could not find a way to set current thread to STA in the project or main form properties but maybe I am looking in the wrong place.
What is the proper way to call saveFileDialog.ShowDialog() in a background thread?
Solution very easy;
Just add this on top of the Main method [STAThread]
So your main method should look like this
[STAThread]
static void Main(string[] args)
{
....
}
It works for me.
ShowDialog() shouldn't be called from a background thread - use Invoke(..).
Invoke((Action)(() => { saveFileDialog.ShowDialog() }));
this should work if you are creating the thread in which you call the showDialog:
var thread = new Thread(new ParameterizedThreadStart(param => { saveFileDialog.ShowDialog(); }));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Add following code on FormLoad
private void Form1_Load(object sender, EventArgs e)
{
Thread myth;
myth = new Thread(new System.Threading.ThreadStart(CallSaveDialog));
myth.ApartmentState = ApartmentState.STA;
myth.Start();
}
Here CallSaveDialog is a thread and here you can call ShowDialog like this
void CallSaveDialog(){saveFileDialog.ShowDialog();}
On your MainForm:
if (this.InvokeRequired) {
this.Invoke(saveFileDialog.ShowDialog());
} else {
saveFileDialog.ShowDialog();
}
Or, if you will have other methods that need to be run from the UI thread:
private void DoOnUIThread(MethodInvoker d) {
if (this.InvokeRequired) { this.Invoke(d); } else { d(); }
}
Then, call your method as such:
DoOnUIThread(delegate() {
saveFileDialog.ShowDialog();
});

Application.ThreadException event for ALL GUI threads

I have a WinForms application that creates a multiple forms, each in their own GUI thread, (not the main GUI thread). I would like to handle the Unhandled Exception event (Application.ThreadException) for all these forms to handle any errors. I would also like to handle exceptions from worker threads - this bit seems to be working correctly, but I'm having trouble with exceptions from GUI threads still:
Program.cs:
[STAThread]
static void Main()
{
AttachExceptionHandlers();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public static void AttachExceptionHandlers()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Dispatcher.CurrentDispatcher.UnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(CurrentDispatcher_UnhandledException);
}
Form1.cs:
//GUI Thread Crash
private void button1_Click(object sender, EventArgs e)
{
object a = null;
a.ToString();
}
//Worker Thread Crash
private void button2_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(() =>
{
object a = null;
a.ToString();
});
myThread.Start();
myThread.Join();
}
//New Thread, New Gui Crash
private void button3_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(() =>
{
using (CrashingForm form = new CrashingForm()) //Crashing Form Crashes in it's FormLoad event.
{
Application.Run(form);
}
});
myThread.Start();
myThread.Join();
}
This code will call my exception handler in the first 2 instances (GUI Thread Crash and Worker Thread Crash) but does not handle the third instance where a new GUI thread is created. I have found that if I call Program.AttachExceptionHandlers(); before the Application.Run(form) line, all is OK, but this is undesirable as I would have to implement some logic to make sure the call to Program.AttachExceptionHandlers() is made before we call a form is created on each thread (the call to Application.SetUnhandledExceptionMode fails if called after creating a form on the thread).
This example is part of a bigger bit of code which would ideally give the user of my code a simple API to call at the start of their application (like in Program.cs) to attach exception handlers. The exception handler then does some magic to record details about the exception being thrown before the application dies. So telling the user they have to track down each time they create a new GUI thread (worker threads don't seem to be effected by this issue) and reattach the Application.ThreadException Handler is not such a clean solution.
Is there another way to achieve this, without having to re registerer for the Application.ThreadException event each time a new GUI thread is created?
Is there another way to achieve this, without having to re registerer
for the Application.ThreadException event each time a new GUI thread
is created?
I'm not aware of any, and my teammate and I have spent a good amount of time looking into it. .NET WinForms doesn't appear to be very opinionated when it comes to how to create / manage / destroy multiple message pumps.
We use framework methods similar to the one below, in addition to Retlang's WinFormsFiber.
using System;
using System.Threading;
using System.Windows.Forms;
internal static class Program
{
[STAThread]
private static void Main()
{
CreateFormAndStartMessagePump(() => CreateForm("first"), OnException, OnException, false, "pumpThread1");
CreateFormAndStartMessagePump(() => CreateForm("second"), OnException, OnException, false, "pumpThread2");
// note app shutdown not handled here
}
private static T CreateFormAndStartMessagePump<T>(
Func<T> createForm,
ThreadExceptionEventHandler onThreadException,
UnhandledExceptionEventHandler onDomainException,
bool isBackground,
string name) where T : Form
{
var latch = new ManualResetEvent(false);
T form = null;
var thread = new Thread(ts =>
{
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += onThreadException;
AppDomain.CurrentDomain.UnhandledException += onDomainException;
form = createForm();
latch.Set();
Application.Run();
})
{
IsBackground = isBackground,
Name = name
};
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
latch.WaitOne();
return form;
}
private static Form CreateForm(string name)
{
var form = new Form();
form.Text = name;
form.Show();
return form;
}
private static void OnException(object sender, UnhandledExceptionEventArgs e)
{
// ...
}
private static void OnException(object sender, ThreadExceptionEventArgs e)
{
// ...
}
}

I get an error about using a different thread?

When I click my ActionButton, there is a timer that starts and after 3 seconds, it must fire a methode to change the current ContentPage to the another page.
But i get a message : The calling thread cannot access this object because a different thread owns it. I dont understand what i am doing wrong. But if i put the ChangeContent() method in the click_event, it works, but in the _tm_elapsed it doenst work?
using smartHome2011.FramePages;
using System.Timers;
public partial class AuthenticationPage : UserControl
{
private MainWindow _main;
private Storyboard _storyboard;
private Timer _tm = new Timer();
private HomeScreen _homeScreen = new HomeScreen();
public AuthenticationPage(MainWindow mainP)
{
this.InitializeComponent();
_main = mainP;
}
private void ActionButton_Click(object sender, System.EventArgs eventArgs)
{
_main.TakePicture();
identifyBox.Source = _main.source.Clone();
scanningLabel.Visibility = Visibility.Visible;
_storyboard = (Storyboard) FindResource("scanningSB");
//_storyboard.Begin();
Start();
}
private void Start()
{
_tm = new Timer(3000);
_tm.Elapsed += new ElapsedEventHandler(_tm_Elapsed);
_tm.Enabled = true;
}
private void _tm_Elapsed(object sender, ElapsedEventArgs e)
{
((Timer) sender).Enabled = false;
ChangeContent();
//MessageBox.Show("ok");
}
private void ChangeContent()
{
_main.ContentPage.Children.Clear();
_main.ContentPage.Children.Add(_homeScreen);
}
}
Description
You have to use Invoke to ensure that the UI Thread (the thread who has created your Control) will execute that.
1. If you are doing Windows Forms then do this
Sample
private void ChangeContent()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(ChangeContent));
return;
}
_main.ContentPage.Children.Clear();
_main.ContentPage.Children.Add(_homeScreen);
}
2. If you are doing WPF then do this
private void _tm_Elapsed(object sender, ElapsedEventArgs e)
{
((Timer) sender).Enabled = false;
this.Dispatcher.Invoke(new Action(ChangeContent), null);
//MessageBox.Show("ok");
}
More Information
Windows Forms
MSDN - Control.Invoke Method
MSDN - Control.InvokeRequired Property
WPF
MSDN - Dispatcher.Invoke Method
MSDN - Dispatcher Class
The logic executed in the Elapsed event of the Timer is run on a separate thread from the rest of your code. This thread cannot access objects on the main/GUI thread.
This thread should help you find out how to do it: How to update the GUI from another thread in C#?
I suspect you are using a System.Threading.Timer. You can avoid cross thread operation by just using a Windows.Forms timer:
http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx
That timer uses regular messages and the event occours on the same thread of the UI.
The event to use is no more called "Elapsed", but "Tick" read the doc here: http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.tick.aspx

How can I create WPF controls in a background thread?

I have method which create background thread to make some action. In this background thread I create object. But this object while creating in runtime give me an exception :
The calling thread must be STA, because many UI components require this.
I know that I must use Dispatcher to make reflect something to UI. But in this case I just create an object and dont iteract with UI. This is my code:
public void SomeMethod()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(Background_Method);
worker.RunWorkerAsync();
}
void Background_Method(object sender, DoWorkEventArgs e)
{
TreeView tv = new TreeView();
}
How can I create objects in background thread?
I use WPF application
TreeView is a UI control. You can only create and manipulate UI controls on a UI thread, so what you're trying to do is not possible.
What you want to do is do all of the time-consuming work on the background thread, and then "call back" to the UI thread to manipulate the UI. This is actually quite easy:
void Background_Method(object sender, DoWorkEventArgs e)
{
// ... time consuming stuff...
// call back to the window to do the UI-manipulation
this.BeginInvoke(new MethodInvoker(delegate {
TreeView tv = new TreeView();
// etc, manipulate
}));
}
I may have got the syntax wrong for BeginInvoke (it's off the top of my head), but there you go anyway...
HTH:
void Background_Method(object sender, DoWorkEventArgs e)
{
// Time Consuming operations without using UI elements
// Result of timeconsuming operations
var result = new object();
App.Current.Dispatcher.Invoke(new Action<object>((res) =>
{
// Working with UI
TreeView tv = new TreeView();
}), result);
}
No one is discussing the case of a separate STA thread in details (even though the concept is exactly the same).
So let's imagine a simple tab control added at a button click
private void button_Click(object sender, RoutedEventArgs e)
{
TabItem newTab = new TabItem() { Header = "New Tab" };
tabMain.Items.Add(newTab);
}
If we move it to another STA thread
private void button_Click(object sender, RoutedEventArgs e)
{
Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint));
newThread.SetApartmentState(ApartmentState.STA);
newThread.IsBackground = true;
newThread.Start();
}
private void ThreadStartingPoint()
{
TabItem newTab = new TabItem() { Header = "New Tab" };
tabMain.Items.Add(newTab);
}
of course we get a System.InvalidOperationException
Now, what happens if we add the control
private void AddToParent(string header)
{
TabItem newTab = new TabItem() { Header = header };
tabMain.Items.Add(newTab);
}
using a delegate method?
public void DelegateMethod(string header)
{
tabMain.Dispatcher.BeginInvoke(
new Action(() => {
this.AddToParent(header);
}), null);
}
it does work if you call it
private void button_Click(object sender, RoutedEventArgs e)
{
Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint));
newThread.SetApartmentState(ApartmentState.STA);
newThread.IsBackground = true;
newThread.Start();
}
private void ThreadStartingPoint()
{
DelegateMethod("new tab");
}
because of course now we keep the visual tree in the same original thread.
To make your code simply work, you must join a STA COM apartment by calling Thread.SetApartmentState(ApartmentState.STA). Since BackgroundWorker is probably using some shared thread pool, joining a particular apartment may affect other users of this thread pool or may even fail if it has already been set to e.g. MTA before. Even if it all worked out, your newly created TreeView would be locked to this worker thread. You wouldn't be able to use it in your main UI thread.
If you explained in a bit more detail about your true intentions, you would surely get better help.
Try following Code:
public void SomeMethod()
{
System.ComponentModel.BackgroundWorker myWorker = new System.ComponentModel.BackgroundWorker();
myWorker.DoWork += myWorker_DoWork;
myWorker.RunWorkerAsync();
}
private void myWorker_DoWork(object sender,
System.ComponentModel.DoWorkEventArgs e)
{
// Do time-consuming work here
}
void Background_Method(object sender, DoWorkEventArgs e)
{
TreeView tv = new TreeView();
// Generate your TreeView here
UIDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
someContainer.Children.Add(tv);
};
}
I solved my problem. I just used e.Result property of RunWorkerCompleted method. I get data in background thread and then use this data when thread completed. Thank every body for useful methods. Special thank to Veer to give a recommendation about e.Result property.
See the answer on this question:
How to run something in the STA thread?
When you define your thread, set the ApartmentState to STA:
thread.SetApartmentState(ApartmentState.STA);
This should do the trick!

C# Windows Form created by EventHandler disappears immediately

I don't know why this is happening, but when I create a new form inside an EventHandler, it disappears as soon as the method is finished.
Here's my code. I've edited it for clarity, but logically, it is exactly the same.
static void Main()
{
myEventHandler = new EventHandler(launchForm);
// Code that creates a thread which calls
// someThreadedFunction() when finished.
}
private void someThreadedFunction()
{
//Do stuff
//Launch eventhandler
EventHandler handler = myEventHandler;
if (handler != null)
{
handler(null, null);
myEventHandler = null;
}
}
private void launchForm(object sender, EventArgs e)
{
mf = new myForm();
mf.Show();
MessageBox.Show("Do you see the form?");
}
private myForm mf;
private EventHandler myEventHandler;
The new form displays as long as the MessageBox "Do you see the form?" is there. As soon as I click OK on it, the form disappears.
What am I missing? I thought that by assigning the new form to a class variable, it would stay alive after the method finished. Apparently, this is not the case.
I believe the problem is that you are executing the code within the handler from your custom thread, and not the UI thread, which is required because it operates the Windows message pump. You want to use the Invoke method here to insure that the form gets and shown on the UI thread.
private void launchForm(object sender, EventArgs e)
{
formThatAlreadyExists.Invoke(new MethodInvoker(() =>
{
mf = new myForm();
mf.Show();
MessageBox.Show("Do you see the form?");
}));
}
Note that this assumes you already have a WinForms object (called formThatAlreadyExists) that you have run using Application.Run. Also, there may be a better place to put the Invoke call in your code, but this is at least an example of it can be used.
I think if you create a form on a thread, the form is owned by that thread. When creating any UI elements, it should always be done on the main (UI) thread.
this looks as if you are not on the form sta thread so once you show the form it is gone and the thread finishes it's job it kills it self since there is nothing referenceing the thread. Its not the best solution out there for this but you ca use a showdialog() rather than a show to accomplish it keeping state if you need a code example i use this exact same process for a "loading...." form
public class Loading
{
public delegate void EmptyDelegate();
private frmLoadingForm _frmLoadingForm;
private readonly Thread _newthread;
public Loading()
{
Console.WriteLine("enteredFrmLoading on thread: " + Thread.CurrentThread.ManagedThreadId);
_newthread = new Thread(new ThreadStart(Load));
_newthread.SetApartmentState(ApartmentState.STA);
_newthread.Start();
}
public void Load()
{
Console.WriteLine("enteredFrmLoading.Load on thread: " + Thread.CurrentThread.ManagedThreadId);
_frmLoadingForm = new frmLoadingForm();
if(_frmLoadingForm.ShowDialog()==DialogResult.OK)
{
}
}
/// <summary>
/// Closes this instance.
/// </summary>
public void Close()
{
Console.WriteLine("enteredFrmLoading.Close on thread: " + Thread.CurrentThread.ManagedThreadId);
if (_frmLoadingForm != null)
{
if (_frmLoadingForm.InvokeRequired)
{
_frmLoadingForm.Invoke(new EmptyDelegate(_frmLoadingForm.Close));
}
else
{
_frmLoadingForm.Close();
}
}
_newthread.Abort();
}
}
public partial class frmLoadingForm : Form
{
public frmLoadingForm()
{
InitializeComponent();
}
}
Is
dbf.Show();
a typo? Is it supposed to be this instead?
mf.Show();
Is it possible that there is another form that you are showing other than the one you intend to show?
You created a window on a non UI thread. When the thread aborts it will take your window along with it. End of story.
Perform invoke on the main form passing a delegate which will execute the method that creates the messagebox on the UI thread.
Since the MessageBox is a modal window, if dont want the launchForm method to block the background thread, create a custom form with the required UI and call show() on it, not ShowDialog().

Categories