Why do I need a UI Thread check - c#

To update the UI from an other thread you need to call the BeginInvoke method of the dispatcher. Before you invoke you method you can check whether the calling thread is associated with the dispatcher.
For my example I have 2 ways to update a textbox; by clicking a button and by elapsing a timer. The Code:
using System;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private int i = 0;
private TextBlock myText = new TextBlock();
private Button myButton = new Button();
private Timer timer = new Timer(2 * 1000);
private StackPanel panel = new StackPanel();
public MainWindow()
{
InitializeComponent();
myButton.Content = "Click";
panel.Children.Add(myText);
panel.Children.Add(myButton);
this.AddChild(panel);
myButton.Click += (_, __) => IncrementAndShowCounter();
timer.Elapsed += (_, __) => IncrementAndShowCounter();
timer.Start();
}
private void IncrementAndShowCounter()
{
i++;
if (this.Dispatcher.CheckAccess())
{
myText.Text = i.ToString();
}
else
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
myText.Text = i.ToString();
}));
}
}
}
}
When I don't CheckAccess() and just always execute the BeginInvoke everything works fine.
So my question is why not always use the BeginInvoke and skip the CheckAccess?

So my question is why not always use the BeginInvoke and skip the
CheckAccess?
That's exactly what you should do most of the time if invoking is required (i.e. you are touching a control owned by another thread). If invoking is not required then you should skip both of them.
Using CheckAccess implies that your code doesn't know or doesn't want to assume that it will run on the "correct" thread. There are two main reasons for this: genericity (your code is in a library and you can't predict how it will be used) and convenience (you want only one method to take care of both cases, or you want the freedom to change the mode of operation without breaking the program).
Your example falls in the second category: the same method services both modes of operation. In this case you have three possible options:
Always invoke without CheckAccess.
This is going to give you a performance hit (a negligible one here), and it will also make readers of the code assume that the method is only called from worker threads. Since the only benefit is that you will be writing a little less code, this is the worst option.
Keep everything as it is.
Since IncrementAndShowCounter is called from both UI and worker threads, making it adapt to the situation lets you move on to other problems. This is simple and good; it's also the best you can do when writing library code (no assumptions allowed).
Never invoke from within the method, do it from outside as required.
This is the best option on technical merit: since you know the context in which the method will be called, arrange for the invocation to happen outside it. This way the method is not tied to any specific thread and you don't get unnecessary performance penalties.
Here's example code for the third option:
private void IncrementAndShowCounter()
{
i++;
myText.Text = i.ToString();
}
myButton.Click += (_, __) => IncrementAndShowCounter();
timer.Elapsed += (_, __) => Dispatcher.BeginInvoke(IncrementAndShowCounter);

If you 100% sure that the calling thread is UI thread - you can use the "DO" method directly.
If you 100% sure that the calling thread is not UI thread, but the operation should be done on the UI thread, you just call the BeginInvoke
....
// 100% I'm sure the Click handler will be invoked on UI thread
myButton.Click += (_, __) => IncrementAndShowCounter();
// here I'm not sure
timer.Elapsed += (_, __) => Dispatcher.BeginInvoke(IncrementAndShowCounter);
// 100% not UI thred here:
Task.Factory.StartNew(() => Dispatcher.BeginInvoke(IncrementAndShowCounter), TaskScheduler.Default)
private void IncrementAndShowCounter()
{
i++;
myText.Text = i.ToString();
}

Related

The calling thread cannot access this object because a different thread owns it.' error in Thread wpf

I have Window 1 in which on button click i am opening Window 2 in new thread.
Following is my code
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
Scanner w = new Scanner();
w.Show();
w.Closed += (sender2, e2) =>
w.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
Window 2 has form I am getting form values on Button click
private void EnterProduct(object sender, RoutedEventArgs e)
{
var data = ProductDetailsData;
LoadCurrentBetween objMain = new LoadCurrentBetween(); //new MainWindow();
objMain.fillorderform(data);
}
on button click of window 2 i am passing values of form to another View
public void fillorderform(dynamic data)
{
this.Dispatcher.Invoke(() =>
{
LoadCurrentdetails.Part = data.Part;
LoadCurrentBetween loadCurrentbtw = new LoadCurrentBetween();
Switcher.Switch(loadCurrentbtw);
});
} public static class Switcher
{
public static MainWindow pageSwitcher;
public static void Switch(UserControl newPage)
{
pageSwitcher.Navigate(newPage);
}
}
Following code is giving error at "this.Content = nextPage;"
The calling thread cannot access this object because a different thread owns it.
public void Navigate(UserControl nextPage)
{
this.Dispatcher.Invoke(() =>
{
var aa = nextPage.Dispatcher.CheckAccess();
this.Content = nextPage;
});
}
I have seen similar Questions asked by other developers but i am not getting how to fix.
pls help
WPF is very strict (compared to Windows forms) about requiring methods which update UI elements to be done on the main/UI thread. So you definitely want both windows to be in the main/UI thread. The error that you are seeing is what happens if you try to do UI work in WPF from a different thread, so you absolutely have to stop doing that. It's OK to have multiple windows open, all on the same UI thread.
If one of your windows is doing heavyweight processing that makes the UI lock up, then the easiest thing is probably to add the async keyword to your button click event, and put the work you are doing in another method which has an async keyword. Then, when you call the helper method, you use the await keyword.
I agree with others that BackgroundWorker and Task are two other ways to accomplish heavyweight processing in a background thread while still having a responsive UI. Tasks are easier to use than BackgroundWorker.
If you are using a BackgroundWorker, it may be good enough to use the RunWorkerCompleted event. If so, look at this post: How to use WPF Background Worker. If you are using a BackgroundWorker and you need to call a custom method in your UI class from the background thread, then pass the Dispatcher object for your window/dialog to the background thread (or get access to it some other way), and when it needs to call back into the UI, use Invoke with the Dispatcher object. By using Invoke, the method you are calling from the background thread will be executed on the UI thread.

Does threading in c# carry to other methods?

Issue
I am streaming my camera out and want it to run on a separate thread as my UI is freezing. If I start a Thread on the first method call, does the methods inside that method go into the new thread or the old thread?
This is my setup at the moment.
Code
When the user clicks 'Start Stream':
Thread thread = new Thread(new ThreadStart(StartNewStream));
thread.Name = "streammm";
thread.Start();
This calls 'StartNewStream' method which calls other methods:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
win.OnSamplesAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushAudio(e.Samples);
};
Do the methods PushVideo and PushAudio get called in the UI thread or the newly created thread?
If I go into the PushVideo method and put the code:
Thread TR = Thread.CurrentThread;
string _name = TR.name;
The name is now null?
Anyone help on what I am doing wrong?
Whichever thread invokes the OnSampleAvailable event or delegate will also execute its handlers. It does not matter which thread assigns the handlers.
You must understand what your code actually does:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
This does not call anything at first. It only assigns an anonymous method (s, e) => { ... } as a handler to the event cam.OnSampleAvailable.
The handler is not called here. The assignment completes and as the end of your StartNewStream method is reached, your new thread ends. Then, much later, there may be samples available on your cam. Whichever thread is responsible (we do not know) will invoke the cam.OnSampleAvailable event, and the handler (the anonymous method (s, e) => { ... } you assigned earlier) will be executed by that unknown thread.
It depends on the implementation of cam and win. Likey either those two events are running on their own thread pool thread or they may run on the UI thread if they are written in a way that knows how to capture the OperationContext

How to ask the GUI thread to create objects?

I've got the following program flow in my Windows Forms application (WPF is not a viable option unfortunately):
The GUI Thread creates a splash screen and a pretty empty main window, both inheriting Form.
The splash screen is shown and given to Application.Run().
The splash screen will send an event which triggers an async Event Handler which performs initialization, using the IProgress interface to report progress back to the GUI. (This works flawlessly.)
At some point during the initialization, I need to dynamically create GUI components based on information provided by certain plugins and add them to the Main Window.
At this point I'm stuck: I know I need to ask the GUI thread to create those components for me, but there is no Control I could call InvokeRequired on. Doing MainWindow.InvokeRequired works neither.
The only idea I could come up with was to fire an event which is connected to a factory in the GUI Thread, and then wait for that factory to fire another event which provides the created controls. However I am pretty sure there is a more robust solution. Does anyone know how to achieve this?
Using the comments on my question, especially the note about the continuation method which made me find this very useful question, I achieved the following:
The first part of initialization is performed asynchronously (no change).
The second part of the initialization (which creates the UI elements) is performed afterwards as a Continuation Task, in the context of the UI thread.
Apart from the rather short GUI initialization part, the Splash Screen is responsive (i.e. the mouse cursor does not change to "Waiting" once it hovers the Splash Screen).
Neither of the initialization routines knows the splash screen at all (i.e. I could easily exchange it).
The core controller only knows the SplashScreen interface and does not even know it is a Control.
There currently is no exception handling. This is my next task but doesn't affect this question.
TL;DR: The code looks somewhat like this:
public void Start(ISplashScreen splashScreen, ...)
{
InitializationResult initializationResult = null;
var progress = new Progress<int>((steps) => splashScreen.IncrementProgress(steps));
splashScreen.Started += async (sender, args) => await Task.Factory.StartNew(
// Perform non-GUI initialization - The GUI thread will be responsive in the meantime.
() => Initialize(..., progress, out initializationResult)
).ContinueWith(
// Perform GUI initialization afterwards in the UI context
(task) =>
{
InitializeGUI(initializationResult, progress);
splashScreen.CloseSplash();
},
TaskScheduler.FromCurrentSynchronizationContext()
);
splashScreen.Finished += (sender, args) => RunApplication(initializationResult);
splashScreen.SetProgressRange(0, initializationSteps);
splashScreen.ShowSplash();
Application.Run();
}
It is much easier to manage multiple forms and display one while the other is working or being constructed.
I suggest you try the following:
When application is started you create splash screen form so your Program.cs is like this
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SplashForm());
}
Inside the splash form constructor, create a new thread (I will use BackgroundWorker but there are other options like tasks) to build your main form.
public SplashForm()
{
InitializeComponent();
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();
}
Now we need to write the SplashForm member functions to tell background worker what to do
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
// Perform non-GUI initialization - The GUI thread will be responsive in the meantime
// My time consuming operation is just this loop.
//make sure you use worker.ReportProgress() here
for (int i = 1; (i <= 10); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(500);
worker.ReportProgress((i * 10));
}
}
SetVisible(false);
MainForm mainForm = new MainForm();
mainForm.ShowDialog();
//instead of
//this.Visible = false;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
You might have noticed by now, I am using another member function to hide the splash screen. It is because you are now in another thread and you can't just use this.visible = false;. Here is a link on the matter.
delegate void SetTextCallback(bool visible);
private void SetVisible(bool visible)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetVisible);
this.Invoke(d, new object[] { visible });
}
else
{
this.Visible = visible;
}
}
When I run this sample project it shows the progress bar and then loads the MainForm windows form after hiding the SplashForm.
This way you can put any controls that you might need inside the MainForm constructor. The part you shortened as // Perform GUI initialization afterwards in the UI context should go into MainForm constructor.
Hope this helps.

Running a method with parameters in a thread in c#

I am currently working on a project in C#. I have a method called updateProgress() which has two int parameters (count and totalRows).
If I have call the method by saying updateProgress(count, totalRows) this works fine but I want to run this method within a new thread.
How can I go about doing this, I have looked online and everything looks overly complicated for what I am wanting to do.
Thanks for your help with this
Something like this:
new Thread(delegate () {
updateProgress(count, totalRows);
}).Start();
Be aware that threading actually is quite a complex topic, so if you have troubles understanding the asynchronous APIs available in the .NET Framework, I doubt if you should start using threads in the first place.
Anyway, you have several options:
Spin off a thread by your own (like cdhowie pointed out), which is rather discouraged.
Use the TPL (task parallel library) if you are running on .NET 4. Here is a good introduction.
TaskFactory.StartNew(() => updateProgress(count, totalRows));
Use the ThreadPool if you are running on an older version of .NET.
ThreadPool.QueueUserWorkItem(s => updateProgress(count, totalRows));
Of course there are other ways too, but this are imo the most important ones.
Best Regards,
Oliver Hanappi
This has been almost a year, and my answer will not add anything "new" to what has already been said in other answers.
If someone is using .Net 4.0 or higher, best options would be to use a task and let the framework decide the best, by calling TaskFactory.StartNew(...). For older versions, still it's better to utilize the thread pool by using ThreadPool.QueueUserWorkItem(...).
Now, if still someone wants to use the thread in the basic way (creating new thread) for some reason, then this
new Thread(delegate () {
updateProgress(count, totalRows);
}).Start();
can be written in a little cleaner way, using the lambda expression, like this
new Thread(() => updateProgress(count, totalRows)).Start();
There are different ways to run a method in a different thread, like Thread, BackgroundWorker, ThreadPool or Task. Which one to choose depends of various things.
From the name of the method, it sounds like the method should show some progress in the GUI of your application. If that's the case, you have to run the method on the GUI thread. If you want to call it from another thread, you have to use Dispatcher.Invoke() in WPF and Control.Invoke() in WinForms.
try following
ThreadPool.QueueUserWorkItem((o) => { updateProgress(5, 6); });
Here's a more complex example without anonymous delegates. Look at result in the completed function.
using System;
using System.Threading;
using System.ComponentModel;
class Program
{
static BackgroundWorker _bw;
static void Main()
{
_bw = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_bw.DoWork += bw_DoWork;
_bw.ProgressChanged += bw_ProgressChanged;
_bw.RunWorkerCompleted += bw_RunWorkerCompleted;
_bw.RunWorkerAsync ("Hello to worker");
Console.WriteLine ("Press Enter in the next 5 seconds to cancel");
Console.ReadLine();
if (_bw.IsBusy) _bw.CancelAsync();
Console.ReadLine();
}
static void bw_DoWork (object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i += 20)
{
if (_bw.CancellationPending) { e.Cancel = true; return; }
_bw.ReportProgress (i);
Thread.Sleep (1000); // Just for the demo... don't go sleeping
} // for real in pooled threads!
e.Result = 123; // This gets passed to RunWorkerCompleted
}
static void bw_RunWorkerCompleted (object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
Console.WriteLine ("You canceled!");
else if (e.Error != null)
Console.WriteLine ("Worker exception: " + e.Error.ToString());
else
Console.WriteLine ("Complete: " + e.Result); // from DoWork
}
static void bw_ProgressChanged (object sender,
ProgressChangedEventArgs e)
{
Console.WriteLine ("Reached " + e.ProgressPercentage + "%");
}
}

C# threading issue

To play a bit with threading, delegates and backgroundworkers, I'm putting together a few small applications, I'm having a bit of trouble with one of them.
I've a Windows form, with a textbox, a button and a richttext.
When I press the button, the text in the textbox is used as a paramter to instantiate a class, like this:
public partial class Form1 : Form
{
private BackgroundWorker backgroundWorker;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(worker_DoWork);
backgroundWorker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.AppendText(response);
Application.DoEvents();
}
});
}).Start();
}
void OnUpdateTicker(string msg)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
label4.Text = msg;
Application.DoEvents();
});
}).Start();
}
}
When debugging I run into a 'textBox1.Lines' threw an exception of type 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException'
Any tips on how to solve this problem?
First, there is no need to create new threads inside DoWork; the whole idea with the BackgroundWorker is that DoWork is executed on a separate thread. Second, since DoWork is executed on a separate thread and UI controls can be modified only on the UI thread, you need to invoke those updates correctly. So, a rewritten version of worker_DoWork could look like this:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.Invoke((Action) delegate { richTextBox1.AppendText(response); });
}
}
Note how the code does not explicitly spawn any new threads, and also how the AppendText method call is done through a Control.Invoke call, forcing it to execute on the UI thread.
The main reason is that the textbox is not owned by the background thread.
Your UI thread owns all the UI objects, and you're spinning up a background thread when a button is pressed. That background thread should not have access to any UI objects.
If you want the value of the textbox to be used, you'll need to pass it to your background thread another way.
Have a look here for an explanation (and solution).
You can only update controls on the main thread from the main thread itself, unless you explicitly tell your program that it's ok to do, by using the .Invoke method of the control.
From: http://www.albahari.com/threading/part3.aspx
Control.Invoke
In a multi-threaded Windows Forms application, it's illegal to call a method or property on a control from any thread other than the one that created it. All cross-thread calls must be explicitly marshalled to the thread that created the control (usually the main thread), using the Control.Invoke or Control.BeginInvoke method. One cannot rely on automatic marshalling because it takes place too late – only when execution gets well into unmanaged code, by which time plenty of internal .NET code may already have run on the "wrong" thread – code which is not thread-safe.

Categories

Resources