Cannot update Silverlight UI from asynchronous method completed callback - c#

I have inherited some code that queries a DB over a WCF service and then employs a callback when it's done. I am trying to add some code to that callback to update the UI as the data is processed. I'm finding that I cannot get the UI to update during that callback:
client.GetDataAsync();
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted);
void GetDataCompleted(object sender, GetDataCompletedEventArgs e)
{
// Loop through the data
// ...
textBlock1.Text= "test1";
Dispatcher.BeginInvoke(() => textBlock1.Text= "test2" );
var thread = new Thread(() =>
{
// textBlock1.Text= "test3"; (this throws a cross-thread access exception)
Dispatcher.BeginInvoke(() =>
{
textBlock1.Text= "test4";
});
}
thread.Start();
// ...
Debug.WriteLine("done");
}
None of these things update the UI until (apparently) the entire callback is completed. This post:
What thread calls the completed event handler on silverlight WCF calls?
suggests that the callback is running on the main UI thread so that the BeginInvoke call should be unnecessary. Even if I add various delays in the above code, it still doesn't work. Is this possible? Is there a better way to do this?
(This is a follow-up question to this: Multiple asynchronous UI updates in Silverlight)

degorolls is right in suggesting the TPL, your code would look like below (except without the comments)(Also, exceptions MUST be handled in the TPL, so that might make it not worth it, but I dont think it should).
The first methods would remain the same, and yes in event-based async programming thread-safety is taken care of (ie: you always return to the same thread you called out from)
I also noticed that the text output is all doing = instead of +=, but that is probably more of a problem of typing into overflow
So, test1 and test2 will print out at the same time, however everything being spit out from the TPL code should print as it comes in.
UI code should not be doing anything that requires too much time, though...only updating the UI. So, do think of this as a point to refactor?
Let me know if this helps or if I missed what you were looking for.
client.GetDataAsync();
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted);
void GetDataCompleted(object sender, GetDataCompletedEventArgs e)
{
// Loop through the data
// ...
textBlock1.Text= "test1";
//////Dispatcher should not be needed here as this IS on the main UI thread
Dispatcher.BeginInvoke(() => textBlock1.Text= "test2" );
//////Everything that happens here should NOT be on the main UI thread, thus the cross-thread access exception
//////You can do Dispatcher.CheckAccess to determine if you need to invoke or not
//////Notice the newCopyOfDataToBeWritten. This is a closure,
//////so using the same referenced object will result in errant data as it loops
//////Also, doing it this way does not guarantee any order that this will be written out
//////This will utilize the parallel fully, but there are ways to force the order
var task = Task.Factory.StartNew(()=>
{
Dispatcher.BeginInvoke(()=>textBlock1.Text += newCopyOfDataToBeWritten)
}
);
// ...
///////I assume this is the end of the loop?
Debug.WriteLine("done");
}
....
the below dummied-down code based on what you posted seems to work for me
var outsideThread = new Thread(()=>
{
for(int i = 0; i < 20; i++)
{
//This code will show all at once since it is on the main thread,
//which is still running
//If you want this to display one at a time also, then you need
//to use threads and callbacks like below, also
Dispatcher.BeginInvoke(()=>{textBlock1.Text += "outer" + i;});
int newI = i;
var thread = new Thread(() =>
{
System.Threading.Thread.Sleep(1000 * newI);
Dispatcher.BeginInvoke(() =>
{
//This will display as it comes in
textBlock1.Text += "inner" + newI;
});
});
thread.Start();
}
});
outsideThread.Start();

Related

Dispatcher completed event not working as expected

//Code to show a control goes here
var DispatcherOperation = this.ParentWindow.Dispatcher.BeginInvoke((Action)(() =>
{
//Do stuff
}));
DispatcherOperation.Completed += (s, e) =>
{
if (DispatcherOperation.Status == System.Windows.Threading.DispatcherOperationStatus.Completed)
{
//Code to hide control shown above goes here
}
};
What I want is to show a certain control while the stuff needing done is working, and then hide that control when it's done (new stuff will be showing). It's basically like a loading algorithm, I guess.
My understanding of the Dispatcher method BeginInvoke is that it is for performing UI operations asynchronously. Yet when I run this, it appears the entire application freezes while the dispatcher invokes the function. The result is the control I'm trying to show never actually shows.
Why is this?
Please use TaskScheduler to replace your logic. The link from msdn provide a decent example for how it works.
https://msdn.microsoft.com/en-us/library/dd997394(v=vs.110).aspx
Snapshot
var tiledImage = Task.Factory.ContinueWhenAll(
images, (i) => TileImages(i));
// We are currently on the UI thread. Save the sync context and pass it to
// the next task so that it can access the UI control "image1".
var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();
// On the UI thread, put the bytes into a bitmap and
// and display it in the Image control.
var t3 = tiledImage.ContinueWith((antecedent) =>
{
...
...
}, UISyncContext);

Adding text to RichTextBox Async #C / WPF

What I am trying to achieve is to add text after every operation to a RichTextBox.
The problem is, that these operations take some time and instead of viewing the appended text after every operation finishes, I view them all at the end of the routine.
Semi-Pseudo code:
RichTextBox richTextBox = new RichTextBox()
if (Operation1())
{
richTextBox.AppendText("Operation1 finished");
if (Operation2())
{
richTextBox.AppendText("Operation2 finished");
if (Operation3())
{
richTextBox.AppendText("Operation3 finished");
}
}
}
The problem is that I view the appended text of operation 1 & 2 after the operation 3 is finished.
I read somewhere that I need to use something called BackgroundWorker???
Using BackgroundWorker, you would just put the background work into DoWork, and the update into RunWorkerCompleted:
var bw1 = new BackgroundWorker();
var bw2 = new BackgroundWorker();
var bw3 = new BackgroundWorker();
bw1.DoWork += (sender, args) => args.Result = Operation1();
bw2.DoWork += (sender, args) => args.Result = Operation2();
bw3.DoWork += (sender, args) => args.Result = Operation2();
bw1.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation1 ended\n");
bw2.RunWorkerAsync();
}
};
bw2.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation2 ended\n");
bw3.RunWorkerAsync();
}
};
bw3.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation3 ended\n");
}
};
bw1.RunWorkerAsync();
You'll notice that this runs afoul of "DRY". You could always consider abstracting the tasks for each step using something like:
var operations = new Func<bool>[] { Operation1, Operation2, Operation3, };
var workers = new BackgroundWorker[operations.Length];
for (int i = 0; i < operations.Length; i++)
{
int locali = i; // avoid modified closure
var bw = new BackgroundWorker();
bw.DoWork += (sender, args) => args.Result = operations[locali]();
bw.RunWorkerCompleted += (sender, args) =>
{
txt.Text = string.Format("Operation{0} ended\n", locali+1);
if (locali < operations.Length - 1)
workers[locali + 1].RunWorkerAsync();
};
workers[locali] = bw;
}
workers[0].RunWorkerAsync();
You could do the above 3 times, or use ReportProgress to run all tasks in one background thread, and periodically report progress.
The way that WPF (and most other UI frameworks work) is that there is a UI thread, which handles all the UI events (such as button clicking) and UI drawing.
The UI can't draw things if it's busy doing other things. What's happening is this:
You click a button
The UI thread gets a button click message, and invokes your click handler function
Now, the UI can't redraw or perform any other updates until your click handler function finishes.
Your Operation1 function finishes, and you append to the RichTextBox
The UI can't update because it's still stuck running your code
Your Operation2 function finishes, and you append to the RichTextBox
The UI can't update because it's still stuck running your code
Your Operation3 function finishes, and you append to the RichTextBox
Your function finishes, and now the UI thread is free, and it can finally process the updates and redraw itself.
This is why you see a pause and then all 3 updates together.
What you need to do is make the code that takes a long time run on a different thread so that the UI thread can remain free to redraw and update when you'd like it to. This sample program works for me - it requires .NET 4.5 to compile and run
using System.Threading.Tasks;
...
// note we need to declare the method async as well
public async void Button1_Click(object sender, EventArgs args)
{
if (await Task.Run(new Func<bool>(Operation1)))
{
richTextBox.AppendText("Operation1 finished");
if (await Task.Run(new Func<bool>(Operation2)))
{
richTextBox.AppendText("Operation2 finished");
if (await Task.Run(new Func<bool>(Operation3)))
{
richTextBox.AppendText("Operation3 finished");
}
}
}
}
What happens here is that we use the C# magical async feature, and the order of operations goes like this:
You click a button
The UI thread gets a button click message, and invokes your click handler function
Instead of calling Operation1 directly, we pass it to Task.Run. This helper function will run your Operation1 method on a thread pool thread.
We use the magic await keyword to wait for the thread pool to finish executing operation1. What this does behind the scenes is something morally equivalent to this:
suspend the current function - and thus free up the UI thread to re-draw itself
resume when the thing we're waiting for completes
Because we're running the long operations in the thread pool now, the UI thread can draw it's updates when it wants to, and you'll see the messages get added as you'd expect.
There are some potential drawbacks to this though:
Because your Operation1 method is Not running on the UI thread, if it needs to access any UI related data (for example, if it wants to read some text from a textbox, etc), it can no longer do this. You have to do all the UI stuff first, and pass it as a parameter to the Operation1 method
It's generally not a good idea to put things that take a long time (more than say 100ms) into the thread pool, as the thread pool can be used for other things (like network operations, etc) and often needs to have some free capacity for this. If your app is just a simple GUI app though, this is unlikely to affect you.
If it is a problem for you, you can use the await Task.Factory.StartNew<bool>(_ => Operation1(), null, TaskCreationOptions.LongRunning))) instead and each task will run in it's own thread and not use the thread pool any more. It's a bit uglier though :-)

Need Multi threading environment to run single test case i.e need to run single test case on multiple threads

I have Unit Test cases written for wcf services. Now i need to run single test case on multiple threads to check performance. i.e if that particular method is called by multiple users(needs to be a custom no. ie. any number from 20 - 500). How can i achieve this ?
I have gone through the Parallel.For and Task Prallel Library. But not able to get anything fruitful for my requirement.
Well... Hope this helps...
To run a method in other Thread, simply do:
new System.Threading.Thread(() => YourMethodName()).Start();
This can be used multiple times.
Note that this method returns void and does not receive any parameters.
To achieve what you want, you need to do:
for (int i = 0; i <= 500; i++)
{
new System.Threading.Thread(() => YourMethodName()).Start();
}
Notes:
a) With this code, you dont know when a thread will end. To verify when a thread is finished, you need to use the .IsAlive property. Example:
Thread t = new System.Threading.Thread(() => YourMethodName());
t.Start();
To verify:
if (t.IsAlive)
{
// running
}
else
{
// finished
}
2) Exceptions cannot be handled from outside. You need to handle all the exceptions inside the thread, otherwise the program will break if an exception is raised.
3) You can't access UI elements inside the thread. To access the UI elements, you will need to use the Dispatcher.
Edit
You can do more things in other thread than just firing a method.
You can pass parameters:
new System.Threading.Thread(() => YourMethodName(a, b, c)).Start();
You can run more than a single method:
new System.Threading.Thread(() =>
{
YourMethodName(a, b, c);
OtherMethod(a);
}).Start();
And you can receive values returned from the thread:
int x = 0;
new System.Threading.Thread(() => { x = YourMethodName(); }).Start();
To know when the x receive the value from the thread, you can do (lets suppose an int):
int x
{
set { VariableSetted(value); } // fire the method
} // put it in global scope, outside the method body
and
new System.Threading.Thread(() => { x = YourMethodName(); }).Start();
and a method to run when the thread has returned the value:
public void VariableSetted(int x)
{
// Do what you want with the value returned from thread
// Note that the thread started this method, so if you need to
// update UI objects, you need to use the dispatcher.
}
I don't know if you are using WPF to make the UI, but if is, to update the screen you can do this:
new System.Threading.Thread(() =>
{
string result = YourMethodName();
this.Dispatcher.Invoke((Action)(() => { yourTextBox.Text = result; }));
}).Start();
You can also start nested threads (thread inside thread).

Example to see return value in multithread scenario

I have a method. I want to return a value not from the main thread but from separate thread. Can you give example of it?
Easiest way is to check out the Background Worker
//set up your BackgroundWorker
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result != null)
{
//process your e.Result
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do your work here
e.Result = "testing"; //set the result to any object
}
Your question does not make sense. A method returns a value directly to the method that called it, on the same thread.
EDIT: If you want a method to supply a value to the UI thread on WinForms, you can call the BeginInvoke method. For example,
//In some event handler, such as button1_Click:
ThreadPool.QueueUserWorkItem(delegate {
//This code runs on a background thread.
//In it, you can do something that takes
//a long time without freezing the UI. If
//you need to interact with the UI from
//the background thread, use the Invoke
//method, like this:
var text = (string)Invoke(new Func<string>(() => textBox1.Text));
//I assume you'd want to do something more meaningful.
var result = text + Environment.NewLine + new String(text.Reverse().ToArray());
//To send the result back to the UI thread, call BeginInvoke:
BeginInvoke(new Action(delegate {
//This code is back on the UI thread,
//but it can still use the variables
//defined earlier.
label1.Text = result;
});
});
Jon Skeet has an excellent article on threading within .net in general. However, if you would like a more specific answer to a more specific problem, please post more details.
EDIT:
To make have methods return in a thread other than the main thread, all you need is a second thread. Everything done in that thread will be method calls and returns in that separate thread. Passing data between threads is a much more complex and trick subject. As a starting point, again I point to Jon Skeet's article to get a good base understanding. Beyond that, there are general principles that can be helpful, like Asynchronous calls and BackgroundWorkers (also see here)that can be very helpful, but these are only options, there many ways to do this, and how it should be done is very dependent on the situation.
In order for your method to return something from another thread, that other thread must "have" the something, and must indicate that the "something" is ready to be returned. There is no general case of this, but there are specific cases. For instance, a producer/consumer problem where your other thread produces something and puts it into a queue, and the first thread waits until there's something in the queue, takes it out, then returns it.
Another case that makes a little sense is seen in asynchronous ASP.NET pages. The page starts its life normally, issues one or more asynchronous operations, and then returns back to ASP.NET. It does nothing else until all the asynchronous operations have completed. Then, ASP.NET calls a method in the page that retrieves the results of these operation and uses them in the rest of the page.
You may be able to see that these two cases are very different. That's because you seem to have asked a "learning" question that amounts to "I wonder if a method always has to get its return value from the same thread?" But that's not something you ever have to do in real life, not really.
I will add that the Ada programming language includes something like this - someone who's actually used it will have to say whether it was useful. If I recall correctly, one task can rendezvous with another, and pass data between them.
This does what you asked for:
class DoSomething
{
string result;
public void RunAsync()
{
var t = new BackgroundWorker();
t.DoWork += (sender, e) =>
{
result = string.Empty; // your code goes here instead of string.empty
};
t.RunWorkerCompleted += Finished;//BackgroundWorkerFinished(sender, e);
t.RunWorkerAsync();
}
public void Finished(object sender, RunWorkerCompletedEventArgs e)
{
//result has been set, now what?
}
}
Once you get that down this becomes more useful:
public static void RunAsync(this Action ActionToAsync, Action<object, RunWorkerCompletedEventArgs> FinishedAction)
{
var t = new BackgroundWorker();
t.DoWork += (sender, e) => ActionToAsync();
t.RunWorkerCompleted += (sender, e) => FinishedAction.Invoke(sender,e);//BackgroundWorkerFinished(sender, e);
t.RunWorkerAsync();
}

What is the best way to thread work in c#?

What's the best way to thread work (methods) in c#?
For example:
Let's say I have a form and want to load data from db.
My form controls:
- dataGridView (to show data from DB),
- label (loading status) and
- button (start loading).
When I click the button my form is frozen until the task is done. Also the loading status does not change until task is done. I think async threading would be the answer?
So my question: what's the best way to handle this? I know there is a lot stuff about Threading, but what's the difference between them and how do you make it thread safe?
How do you solve this kind of problems?
Best Regards.
If using Windows Forms, you should look at BackrgroundWorker. More generally, it is often useful to use the ThreadPool class. And finally, it is worth to take a look at the new .NET 4's Parallel class.
There is no universal 'best' way to thread work. You just have to try different ways of doing things, I'm afraid.
I particularly like Jeremy D. Miller's continuation idea described at this page (scroll down to find the "continuations" section). It's really elegant and means writing very little boilerplate code.
Basically, when you call "ExecuteWithContinuation" with a Func argument, the function is executed asynchronously, then returns an action when it finishes. The action is then marshalled back onto your UI thread to act as a continuation. This allows you to quickly split your operations into two bits:
Perform long running operation that shouldn't block the UI
... when finished, update the UI on the UI thread
It takes a bit of getting used to, but it's pretty cool.
public class AsyncCommandExecutor : ICommandExecutor
{
private readonly SynchronizationContext m_context;
public AsyncCommandExecutor(SynchronizationContext context)
{
if (context == null) throw new ArgumentNullException("context");
m_context = context;
}
public void Execute(Action command)
{
ThreadPool.QueueUserWorkItem(o => command());
}
public void ExecuteWithContinuation(Func<Action> command)
{
ThreadPool.QueueUserWorkItem(o =>
{
var continuation = command();
m_context.Send(x => continuation(), null);
});
}
}
You'd then use it like this (forgive the formatting...)
public void DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished()
{
DisableUi();
m_commandExecutor.ExecuteWithContinuation(
() =>
{
// this is the long-running bit
ConnectToServer();
// This is the continuation that will be run
// on the UI thread
return () =>
{
EnableUi();
};
});
}
You can use this kind of pattern:-
private void RefreshButton_Click(object sender, EventArgs e)
{
MessageLabel.Text = "Working...";
RefreshButton.Enabled = false;
ThreadPool.QueueUserWorkItem(delegate(object state)
{
// do work here
// e.g.
object datasource = GetData();
this.Invoke((Action<object>)delegate(object obj)
{
// gridview should also be accessed in UI thread
// e.g.
MyGridView.DataSource = obj;
MessageLabel.Text = "Done.";
RefreshButton.Enabled = true;
}, datasource);
});
}
You cannot access your controls from the code that runs in the spun-off thread - the framework does not allow this, which explains the error you are getting.
You need to cache the data retrieved from the db in a non-forms object and populate your UI with data from that object after the background worker thread is done (and handle synchronization for access to that object).

Categories