Multi UI thread in WP8? [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to control some UI elements by a thread and the others by different thread in WP8.
Is there any way to make Muulti UI thread like this? Help me.

In order to update your UI from multiple threads, you can use the Dispatcher
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// Code to modify your UI
}

As I stated in my comment, I think you're thinking about the problem the wrong way. What you want is not actually to have more than one GUI thread, you just want to do the work on some other thread. Let me illustrate this with some pseudo code (untested):
// API method with Thread.Sleep as requested
public static int GetAnswer() {
Thread.Sleep(5000);
return 42;
}
// Code assumes to be inside some kind of "Window" class where there is a Dispatcher
public void SomeButton_OnClick(object sender, EventArgs e) {
Task.Run(() => {
int answer = GetAnswer();
Dispatcher.BeginInvoke(() => {
MyLabel.Text = answer;
});
});
}
And now for the explanation:
What happens here is that there is some button, that when clicked calls a method (GetAnswer) that takes a long time (5 seconds). If that method is called on the GUI thread, the GUI will hang for 5 seconds (not a good thing), so what we instead do is call GetAnswer on another thread (using Task.Run, other possible ways to do this is with queueing on the threadpool manually, but Task.Run has a simple name and is easier to remember when you don't have Visual Studio handy to help you). The thread created by the call to Task.Run then starts working on the answer, and after 5 seconds it completes. However, since it's running on a background thread, you can't update the GUI, so therefore (with help of the Dispatcher) it tells the GUI-thread to update the the text of MyLabel at first chance.
This will give you the ability to call slow methods (either because they do CPU bound work, or they sleep) and then use the result in the GUI.
[Edit]
I read your comment about loading content from the internet, and what you probably want to check out is using async API's instead of synchronous ones. Thus you would be able to write code like this without it blocking the UI at all:
public async void SomeButton_OnClick(object sender, EventArgs e) {
// Because we use await here, the GUI thread will not be blocked
var data = await DownloadFromSomewhereAsync();
// Once the resource is done downloaded, the rest of the method will run on the UI thread
MyLabel.Text = data;
}
Note ofcause, that in order to use async methods your API needs to support it. Or you could simplify the code I posted in my previous example to this:
// API method with Thread.Sleep as requested
public static int GetAnswer() {
Thread.Sleep(5000);
return 42;
}
public async void SomeButton_OnClick(object sender, EventArgs e) {
int answer;
await Task.Run(() => {
answer = GetAnswer();
});
MyLabel.Text = answer;
}
This is because Task.Run returns a Task that can be awaited.

Related

Best way to wait for input without blocking in synchronous code [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
In a WPF desktop app, I need to integrate with a third party API that takes a synchronous callback function. In this callback, I need to display a message provided by the third party software, wait for user input and then return that input to the third party software.
The interaction with the user will be in my main window (not a modal dialog), so the UI thread must not be blocked while in the callback function.
There are a number of ways to do this: threads & AutoResetEvent, DispatcherTimer, etc. But most articles describing these methods were written before the async features of .Net 4.5 were available. Nowadays, is there any reason to do anything more complex than the following?
{
...
// Call 3rd party code passing our callback function
thirdParty.Process(referenceNumber, amount, GetValue))
...
}
// UI sets this variable from the user's input
private string _getValueResponse = null;
// The callback function passed to third party API
private void GetValue(ref ClientInstruction clientInstruction)
{
var message = clientInstruction.Message;
_getValueResponse = null;
// This event passes the 3rd party message to my main window,
// and causes it to prompt for user input.
GetValueRequired?.Invoke(this, new GetValueRequiredEventArgs(message));
var result = Task.Run<string>(
async () => await WaitForGetValueResponse())
.GetAwaiter().GetResult();
// Return user input to the third party code
clientInstruction.EnteredValue = result;
}
private async Task<string> WaitForGetValueResponse()
{
while (_getValueResponse == null)
{
await Task.Delay(100);
}
return _getValueResponse;
}
You can do it with BeginRead like pattern as below
Task.Run(() => thirdParty.Process(referenceNumber, amount, GetValue)))
.ContinueWith();
Task.Run will start new thread to get user input and return control back immediately.
And GetValue must be blocking call since third party software does not expect it async, is't it?
ContinueWith() must be populated with logic that processes user inputs and returns it back to your model
However I'm not sure that this is good. First problem is that Task.Run spawn new thread and UI dialog can fail to be shown properly. However you can handle it with dispatcher in WPF.
I suppose that waiting for user input should be blocking call and there is not too much benefit with non-blocking input.
You are using third party software and writing async GetValue will not work.
What would you like to achieve when saying "non-blocking user input in this case" ?
You are spinning up another thread just to await a result.
To be clear, there are three threads at play here.
Your UI thread
The thread that called your callback
A thread that you spin up with Task.Run()
This third thread is pointless, since all it does is sit and await a result from the UI thread, and the second thread sits and waits for the third thread!
If you are happy for the callback to block while you wait (which you current code does), why not just Sleep?
private void GetValue(ref ClientInstruction clientInstruction)
{
var message = clientInstruction.Message;
_getValueResponse = null;
// This event causes the UI to prompt for input
GetValueRequired?.Invoke(this, new GetValueRequiredEventArgs(message));
//poll for response
while (_getValueResponse == null)
Thread.Sleep(100);
clientInstruction.EnteredValue = _getValueResponse ;
}
However, this feels wrong to me. I doubt your third party API is expecting you to lock its callback thread, especially as it provides you with a context object to set the result?
Can you not just store the ClientInstruction in a member and set it directly from the UI thread?

Async action hangs/deadlocks, why? (not waiting for Result, nor ConfiguringAwait)

First, sorry for yet another "why my async action hangs" question but I believe this question is different enough.
Surveying dozens of similar questions, the problem of async action deadlock is either in locking yourself out (.Result), using limited resources or using library components incorrectly (web requests seems popular). In the following example, I cannot find any from above:
private async Task ExecuteAsync(Task<int> task)
{
// entering on current thread, that is the main UI thread
await task // execute "task" asynchronnously (on a different thread)
.ConfigureAwait(false); // when done, no need to return to main thread
MessageBox.Show("success"); // succes indicator
}
public MainWindow() //wpf window ctor
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var task = new Task<int>(() => 42); // make an Action wrapping sychronnous method
// fire and forget, never caring for .Result, disard even the task
var _ = ExecuteAsync(task).ConfigureAwait(false);
}
I have commented the sample with my best try on exaplaining how things (should) work, but something in my explanation must be wrong. Even though MainWindow ctor does not deadlock, the Action () => 42 is never executed and "success" message is not shown. After some debugging I managed to fix the sample (using Task.FromResult), but I am still not sure what is wrong with it as it is now and even more importantly why.
What is the error in my reasoning and why was the action never executed/finished?
You did not start the task! You only declared it. Simply awaiting it does not "fire" it.
private async Task ExecuteAsync(Task<int> task)
{
// at first do start the task
task.Start();
await task.ConfigureAwait(false);
MessageBox.Show("success");
}
Note that ConfigureAwait(false) does not guarantee that execution will be continued on a different thread. It only says that you don't need it to be resumed on the original thread. And resuming UI work (like MessageBox.Show()) on a non-UI thread is not recommended.
As NineBerry pointed out, if you want to wrap a synchronous method and let it run on a different thread, you should use Task.Run():
var task = Task.Run(() => YourSynchronousCall());

Is this a safe way to update the UI Thread in a Windows Forms application?

I'm not super familiar with multithreading, and want to know if this is the safest way to update the UI thread from a different thread. The workflow of my code is as follows:
// this is the button click action
private async void button_Click(object sender, EventArgs e)
{
//do some things to local variables
await create();
}
// this task creates the thing and does all the heavy processing
public Task create()
{
return Task.Run(() =>
{
try
{
//some code
consoleOut(string);
}
catch (Exception e)
{
//do things
}
}
}
// custom logging that prints formatted stuff out to a ListBox
public void consoleOut(String str)
{
if (this.InvokeRequired)
{
this.Invoke(
new MethodInvoker(
delegate() { consoleOut(str); }));
}
else
{
//print stuff
ListBox.Items.Add(str);
}
}
Is this the safest way to update the contents of my ListBox from create Task?
For reference I combined things from these previous questions, but there wasn't a lot of explanation on what the code did, hence my question about thread safety and if there are better ways:
Make wpf UI responsive when button click is performed
Cross-thread operation not valid
This is how I multithread which has worked 100% great for me... though someone will probably get on here and say it's the worst ever...
//start a second thread with parameters in this case
Thread filterThd = new Thread(() => filterLike(FilterTextBox.Text.ToLower(),column));
filterThd.Start();
//somewhere in your thread, it updates the ui like this
Form2 f2= (Form2)System.Windows.Forms.Application.OpenForms["Form2"];
f2.Invoke((MethodInvoker)(() => f2.DataGrid.DataSource = null));
IMHO, there are two problems with the approach you're taking:
You're overcomplicating things - more on that later,
Depending on what the //some code section does you could end-up with a frozen application.
Now, let's tear each part in its own bits.
The over complication is due to the fact that you're mixing two different ways of doing basically the same thing - namely, the Invoke method and a Task, although the Task-based approach is incomplete.
However, the biggest problem is the part with // some code; as I said before, if that part is heavy on the resources (i.e. takes long to run) you could end up with a frozen application because the thread on which that method is running is the UI thread which consumes the UI resources otherwise allocated for the application to process messages and draw controls.
I would split the code into two logical parts:
one that does the processing and
the other one that logs the string to UI
The code should look like this:
private async void button_Click(object sender, EventArgs e)
{
//do some things to local variables
await Task.Run(() =>
{
// some code
})
.ContinueWith(p => ListBox.Items.Add(str),
TaskScheduler.FromCurrentSynchronizationContext());
}
Aside from removing the clutter the code above splits the work into two tasks which can be scheduled differently: the first one can be executed on a background thread and will not affect the UI while the continuation will run on the UI thread due to the restriction passed via TaskScheduler.FromCurrentSynchronizationContext() allowing you to safely access controls and even though it is executed on the UI thread its execution time is very small thus the application won't freeze.

Label takes long time to change [duplicate]

This question already has an answer here:
Label won't change color until after code is finished executing
(1 answer)
Closed 8 years ago.
I have a problem with my winform app in C#.
In program, i have a label as statusbar and a method like this:
private void btnProcess_Click(object sender, EventArgs e)
{
lblStatus.Text = "Please wait...";
/*
Code here
*/
}
my code process taking a few second but after processing the code, text of label will change and i want it happening before that.
Note: I am an amateur in programming and i cant understand english very well, please explain your solution simply. thank you.
You may be able to hack this using a repaint event by calling Update or Refresh, but the real solution is using a BackgroundWorker for longer operations.
This is not easy stuff, you should find a tutorial for it in a language you understand perfectly.
In winform application (but also in all GUI application) it's not recommended execute long task in the GUI thread. For solving your problem you must use Thread(here you can find the complete mdsn reference).
If you want update the Label from another Thread you' ll do a Cross threading operation. For more information take a look to this question
All the code is always ran and completed before any changes are made to the UI. This is just the basic logic of WinForms and WPF.
You can use "BackgroundWorker", so the longer code is run on another thread. This way you can freely edit the UI-elements while the longer code is still running.
If you are using .Net 4.5, you can use await and async rather than BackgroundWorker.
You would create an async method that returns a Task, and inside that method use Task.Run() to start the background work.
Here's an example. You'd do all the slow work in the lambda passed to Task.Run() where I've commented "Do all your slow work here":
private async void btnProcess_Click(object sender, EventArgs e)
{
lblStatus.Text = "Please wait...";
await doSomeWorkAsynchronously();
lblStatus.Text = "Work completed";
}
private async Task doSomeWorkAsynchronously()
{
await Task.Run(()=>
{
// Do all your slow work here.
Thread.Sleep(5000); // Simulate slow work.
});
}
I think this is a bit easier than using BackgroundWorker.
Note that if all your "slow" methods were already async (e.g. if you are using asynchronous file I/O) then you might just be able to await each of your async operations rather than having to create your own task via Task.Run().
You can also return a value from the background task. Suppose you wanted to return a string with which to update the label when the background task had completed. You could do that as follows:
private async void btnProcess_Click(object sender, EventArgs e)
{
lblStatus.Text = "Please wait...";
lblStatus.Text = await doSomeWorkAsynchronously();
}
private async Task<string> doSomeWorkAsynchronously()
{
return await Task.Run(()=>
{
// Do all your slow work here.
Thread.Sleep(5000); // Simulate slow work.
return "The task completed.";
});
}

how to get a task completion notification in non gui thread

Background: I used to call a stored procedure during my Form Load. However, since this resulted in a suboptimal UI experience, I put my SP call in a task of its own inside the Shown event. Since this is typically the last event in the form display process, it resulted in a much better experience than putting stuff in the Form load event. I have:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(RunSPAndCheckStuff());
// both of below run on the GUI thread.
// if I print the thread ID in mycallback it is the GUI thread id
dbCheckTask.ContinueWith(mycallback());
// I also tried below. But obviously, that too runs on the GUI thread
mycallback(dbCheckTask.Result)
}
Because they fire on the GUI thread, my startup form paint is still neither instantaneous nor smooth. How can I get my task complete callback on a non-GUI thread without resorting to events? Whenever the task completes and if something is wrong and only if something is wrong (bool result returned false) then the user gets a message box pop. Until then he could go ahead and do other non database related stuff on the form. Please advise how I can get a task completion callback with task result in a non gui thread. Thank you
All this stuff is addressed best in the Async language extensions you can download here and has the homepage here.
It introduces the async and await keywords to C# and VB that will let you write code that switches back and forth between UI and background threads effortlessly even within a single method. The compiler will convert that to tasks, continuations, error catching etc etc transparantly without you having to worry about any of that. The example that would interest you would be this one:
public async void AsyncSwitchToCPU() {
Console.WriteLine("On the UI thread.");
// Switch to a thread pool thread:
await new SynchronizationContext().SwitchTo();
Console.WriteLine("Starting CPU-intensive work on background thread...");
int result = DoCpuIntensiveWork();
Console.WriteLine("Done with CPU-intensive work!");
// Switch back to UI thread
await Application.Current.Dispatcher.SwitchTo();
Console.WriteLine("Back on the UI thread. Result is {0}.", result);
}
public int DoCpuIntensiveWork()
{
// Simulate some CPU-bound work on the background thread:
Thread.Sleep(5000);
return 123;
}
This even has a go-live license (with some reservations from MS). Very elegant stuff borrowed from F#.
Rgds Gert-Jan
I'd use a BackgroundWorker for this, personally. One way to get your callback to run on the task thread would be to modify your method call and task creation as follows:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(() => RunSPAndCheckStuff(mycallback));
...
}
private bool RunSPAndCheckStuff(Action<bool> callback)
{
bool result = false;
// Do stuff
callback(result);
return result;
}
You should look into using the Asynchronous API's rather than calling the synchronous versions in a background thread:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.beginexecutenonquery.aspx
The advantage to that is that no thread will be blocked, and I believe the callback will be called on ThreadPool thread, e.g. NOT on the GUI thread. From there you can marshal any GUI calls back to the GUI thread with Invoke/BeginInvoke.
Why not doing:
Task.Factory.StartNew(()=>WorkerMethod());
And define WorkerMethod() as:
void WorkerMethod()
{
RunSPAndCheckStuff(); // this blocks until finished
DoSomeMoreStuff(); // then this continuous
}
Otherwise please provide more details on what do you want to accomplish.

Categories