C# WPF Update UI Application freeze - c#

In C# we know there is multiple Background thread ... so like that can we create multiple UI thread?
and Multiple UI thread helps to update data in observation collection without freeez?
if No. what is the best way to get data from webservice and update to observation collection..
Code:-
Thread lthrThread = new Thread((ThreadStart)delegate
{
string Data = DataFromServer()
this.Dispatcher.BeginInvoke(new Action(() =>
{
UI freeze here for 5 -10 seconds
}));
});
lthrThread.SetApartmentState(ApartmentState.STA);
lthrThread.Start();

UI thread is main thread.You cannot copy of it.If you call your data on ui thread,your application user interface will not respond until it ends.So,you need to create background thread or task that handles data call from webservices.When you get data from webservice pass it to the main thread (UI). You can use Dispatcher for it.
Application.Current.Dispatcher?.BeginInvoke(new Action(() => {
// Pass data to UI here.
}));
or you can use async Task which will be more convenient.

Related

c# - running a function with another thread using UI thread items

I have a public static method within a certain class. and it uses items ( combo box, datagridviews etc' ) created in the UI thread. I want to run this function from a new thread, but I get this message :
"Additional information: Cross-thread operation not valid: Control 'CompanycheckedListBox' accessed from a thread other than the thread it was created on."
how can I run the function from a new thread and still use these items created in the UI thread?
I used this line of code : new Thread(delegate () { functionName();}).Start();
The short answer: you can't. Those components can only be accessed on the ui thread. But there are ways to dispatch you function call onto the ui thread.
Most ui frameworks are completely single threaded. It is not allowed to access any component from a different thread than the ui thread.
You need to dispatch to current ui thread. Looking it at your control names, it looks either like a winforms or a WPF application.
In WinForms you need the following code to dispatch back to the ui thread:
public void UpdateUI(object parameter)
{
if (this.InvokeRequired)
{
Dispatcher.BeginInvoke(new Action(() => UpdateUI(parameter)));
return;
}
// Update or access here
}
In WPF the following snipped allows you to change the ui form a different thread:
public void UpdateUI(object parameter)
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(new Action(() => UpdateUI(parameter)));
return;
}
// Do update or access here
}
The important thing to notice here, is that those functions will be executed on the UI thread and not on the calling thread.
Edit: the object parameter is completely optional. It was intended as a example on how to use this method with a function with parameters.

Using Dispatcher to unblock Wpf Ui

I am working on windows app which generates various results of testing. The UI provides a button Results which has various methods as event handlers. These methods are provided by an API module. The module fetches the data from warehouse and then displays it to the user.
The API call is asynchronous.
But UI gets blocked once the button is clicked.
After quite some readings , I came to know that Dispatcher helps in running a process in background . Dispatcher can be invoked/call only by the UI thread.
How can I implement dispatcher to keep the UI away from being blocked?
The function in c# looks something like this
private async void get_results(object sender, RoutedEventArgs e)
{
List<resultsummary> data = new List<resultsummary>();
if(id==plan_id)
{
data= await getdata.getsummary(id, name);
}
}
Edit:-
This is my understanding of async and await in the above code. But it gives an error cannot await. The getdata class is in differnet namespace and the method getsummary is defined in that space.
The main objective is to unblock the UI and how to go about this using Dispatcher technique?
You don't need to use a Dispatcher to do what you want. In order to fetch data on a background thread and then pass that data from the background thread to the UI thread, you can use the Task class.
Task.Factory.StartNew((Func<YourDataType>)delegate()
{
// Fetch data on background thread here (return YourDataType, whatever that is)
return DataAccessClass.GetData();
}).ContinueWith((Task<YourDataType> task) =>
{
// Update controls with result on UI thread here
YourUiProperty = task.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
Obviously, you'll need to replace the YourDataType type with whatever your data type is.
You can use Action...
Put your code in an Action like this"
Action action = () =>
{
// your code...
};
assume that you have a label to show result
myLabel.Dispatcher.BeginInvoke(action);

creating a UI in background thread WPF?

I tried following:
var task = new Task(() =>
{
for (int i=0; i<10; i++) {
//Create new Grid HERE
// Add Table with some dynamic data here..
// print the above Grid here.
}
});
task.ContinueWith((previousTask) =>
{
label.Content = printerStatus(); // will return "Out of Paper", "printing", "Paper jam", etc.
},
TaskScheduler.FromCurrentSynchronizationContext());
label.Content = "Sending to printer";
It returns following error: The calling thread must be STA, because many UI components require this..
The error occurs when it tries to create a new UI object Grid.
How can i fix this? Let me know if there is any other way arround!
Tasks use thread pool threads, which are in a MTA.
If you want a background STA thread, you will have to create one yourself and explicitly set the ApartmentState.
Thread t = new Thread( ... );
t.SetApartmentState( ApartmentState.STA );
t.Start();
You cannot create UI objects on different thread than the main UI thread because as soon as you add them to the UI, it tries to set the Parent property, and a thread in WPF cannot modify objects that were created on a different thread.
Instead, I'd recommend creating a list or collection of the Grid's Data on the 2nd thread, and binding it to the UI using something like an ItemsControl. This will keep all UI objects on the main UI thread, while background processing can be done on a background thread.
To update a UI object from a background thread, such as your status label, I'd recommend using the Dispatcher like lawrencealan's answer suggests. The Dispatcher is WPF's internal message queue for the main UI thread
Using the Dispatcher for the label and Invoke might help:
label.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
label.Content = printerStatus();
}
));

Running method in the background to update UI

How do I run a method in the background for c# wpf? It is a packet sniffing method which will update the UI whenever new data is received, do I have to use dispatcher.invoke?
You could use the Dispatcher or the BackgroundWorker: See Build More Responsive Apps With The Dispatcher
There are a lot of ways to do this in WPF, but here's one very simple way using Task to do the work on another thread and then dispatching the UI updating back to the main thread:
Task.Factory.StartNew(() =>
{
// some work (packet sniffing)
// update UI
this.Dispatcher.BeginInvoke(new Action(() =>
{
// update my controls here
}));
});

Change WPF controls from a non-main thread using Dispatcher.Invoke

I have recently started programming in WPF and bumped into the following problem. I don't understand how to use the Dispatcher.Invoke() method. I have experience in threading and I have made a few simple Windows Forms programs where I just used the
Control.CheckForIllegalCrossThreadCalls = false;
Yes I know that is pretty lame but these were simple monitoring applications.
The fact is now I am making a WPF application which retrieves data in the background, I start off a new thread to make the call to retrieve the data (from a webserver), now I want to display it on my WPF form. The thing is, I cannot set any control from this thread. Not even a label or anything. How can this be resolved?
Answer comments:
#Jalfp:
So I use this Dispatcher method in the 'new tread' when I get the data? Or should I make a background worker retrieve the data, put it into a field and start a new thread that waits till this field is filled and call the dispatcher to show the retrieved data into the controls?
The first thing is to understand that, the Dispatcher is not designed to run long blocking operation (such as retrieving data from a WebServer...). You can use the Dispatcher when you want to run an operation that will be executed on the UI thread (such as updating the value of a progress bar).
What you can do is to retrieve your data in a background worker and use the ReportProgress method to propagate changes in the UI thread.
If you really need to use the Dispatcher directly, it's pretty simple:
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => this.progressBar.Value = 50));
japf has answer it correctly. Just in case if you are looking at multi-line actions, you can write as below.
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => {
this.progressBar.Value = 50;
}));
Information for other users who want to know about performance:
If your code NEED to be written for high performance, you can first check if the invoke is required by using CheckAccess flag.
if(Application.Current.Dispatcher.CheckAccess())
{
this.progressBar.Value = 50;
}
else
{
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => {
this.progressBar.Value = 50;
}));
}
Note that method CheckAccess() is hidden from Visual Studio 2015 so just write it without expecting intellisense to show it up. Note that CheckAccess has overhead on performance (overhead in few nanoseconds). It's only better when you want to save that microsecond required to perform the 'invoke' at any cost. Also, there is always option to create two methods (on with invoke, and other without) when calling method is sure if it's in UI Thread or not. It's only rarest of rare case when you should be looking at this aspect of dispatcher.
When a thread is executing and you want to execute the main UI thread which is blocked by current thread, then use the below:
current thread:
Dispatcher.CurrentDispatcher.Invoke(MethodName,
new object[] { parameter1, parameter2 }); // if passing 2 parameters to method.
Main UI thread:
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background, new Action(() => MethodName(parameter)));
The #japf answer above is working fine and in my case I wanted to change the mouse cursor from a Spinning Wheel back to the normal Arrow once the CEF Browser finished loading the page. In case it can help someone, here is the code:
private void Browser_LoadingStateChanged(object sender, CefSharp.LoadingStateChangedEventArgs e) {
if (!e.IsLoading) {
// set the cursor back to arrow
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() => Mouse.OverrideCursor = Cursors.Arrow));
}
}

Categories