I have a UserControl at which a message is being appeared gradually and after a few seconds it'll be faded again. This control uses a backgroundWorker. It works all right. But I should add an overload for the method which is responsible for showing the message as:
ShowMessage(string message, bool waitToHide) { .. }
Now, I need to know what the best way to make calling thread (the UI thread) wait for the above method is.
I tried to raise an event to notify the invoking scope that the inside backgroundWorker has completed, but since this method has been used frequently in the main application, I must break many unified scopes into some scattered ones.
{
// before code snippet..
messageDisplayer1.ShowMessage("test", true);
// after code snippet..
}
will turn to:
{
// before..
messageDisplayer1.ShowMessage("test", true);
}
void messageDisplayer1_Done()
{
// after..
}
If you have to stick with .NET 3.5 or .NET 4 without the async CTP, I don't think you will be able to avoid splitting your code (unless you want to litter your code with DoEvents, which is definitely not recommended).
On the other hand, the async extensions (either the CTP for .NET 4 or the version included in .NET 4.5) allow you to do something like this:
{
// before code snippet..
await messageDisplayer1.ShowMessage("test", true);
// after code snippet..
}
Then the compiler automatically puts your "after code snippet" into a separate code block (a continuation), which is run as soon as ShowMessage has signaled completion. In the mean time, control is returned to the Windows message loop, leaving your program's UI responsive.
Related
I have a windows forms application
on which I need to use a for loop having a large number of Remote Calls around 2000 - 3000 calls,
and while executing the for loop, I loose my control on form and form controls, as it becomes a large process and some time it shows "Not Responding" but if I wait for a long it comes back again, I think I need to use some threading model for that, is there any idea, how can I proceed to solve the issue?
You need to perform the long running operation on a background thread.
There are several ways of doing this.
You can queue the method call for execution on a thread pool thread (See here):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
In .NET 4.0 you can use the TaskFactory:
Task.Factory.StartNew(() => YourMethod());
And in .NET 4.5 and later, you can (and should, rather than TaskFactory.StartNew()) use Task.Run():
Task.Run(() => YourMethod());
You could use a BackgroundWorker for more control over the method if you need things like progress updates or notification when it is finished. Drag the a BackgroundWorker control onto your form and attach your method to the dowork event. Then just start the worker when you want to run your method. You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Create a totally new thread for your work to happen on. This is the most complex and isn't necessary unless you need really fine grained control over the thread. See the MSDN page on the Thread class if you want to learn about this.
Remember that with anything threaded, you cannot update the GUI, or change any GUI controls from a background thread. If you want to do anything on the GUI you have to use Invoke (and InvokeRequired) to trigger the method back on the GUI thread. See here.
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker is the easiest way.
Obviously, you need to use background threads. I suggest you read this free e-book.
I'm a newbie in C#, and I'm going to develop a small program using a third party network library to send the requests.
Suppose there have some requests (just simple strings) stored in the queue qTasks, and it will handle those requests one by one with the order as submitted, the queue can be updated during execution, and it should be stopped whenever there has error returned.
I can just use a for loop to call the send request command in the array one by one, but unfortunately the sendrequest command is an async method with callback OnStageChanged, and I need to check the result before sending the next request when the status is "Done".
I'm now using the following method to handle it:
In the main UI Thread,
// Put those request text in a queue names qTasks, then call a goNextTask() to process the request one by one.
// The queue can be updated by the UI thread at anytime, goNextTask will be called periodically to handle those pending request in the queue.
private void goNextTask(bool lastSuccess = true)
{
if (lastSuccess)
{
if (qTasks.Count > 0)
{
// continue to next request
string requestText = qTasks.Dequeue();
SendRequest(requestText, OnStageChangeHandler);
} else {
// Report for all request sent successfully
}
} else {
// stop and show error
}
}
The callback method OnStageChangeHandler will be called by the library whenever the stage changes, and it will have state "Done" when completed.
private void OnStageChangeHandler(object sender, StageChangeEventArgs e)
{
if (e.newState == SessionStates.Done)
{
// check result here
bool success = <...>
// then call the goNextTask in UI thread with the result of current request.
Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
(Action)(() => goNextTask(success)));
}
}
Although it works fine now, I think it's a little bit stupid as it has a somewhat recursive flow (A -> B -> A -> B ->....).
I learnt that MS has improved the web request handling, so that it can work in sync mode.
I'd like to know if I can have a wrapper to make the above async call work as a sync call, so that it can be done in a simple flow as a loop like that:
while (qTaks.Count > 0)
{
if (!sendAndWaitReturn(qTasks.Dequeue())) {
// Report error and quit
}
}
// all tasks completed
This sendAndWaitReturn method will send the request, then wait for the status "Done", and then return the result.
I found some example that may use a control flag to indicate the status of the current request, and the callback function will update this control flag, while the UI thread will loop on this flag using a while loop:
while (!requestDone);
so that it will not continue to nextRequest until requestDone. But in this case, the UI will be blocked.
Is there any better way to convert the async call to work as a sync call without blocking the UI thread?
The difficulty you're going to run into is you have conflicting desires. On one hand, you want to avoid blocking the UI thread. On the other hand, you don't want to run things asynchronously and so you're going to block the UI thread.
You're going to have to pick one, and there's absolutely no reason to keep on doing things synchronously (especially in light of blocking the UI thread). If it hurts when you do that, don't do that.
You haven't specified, but I'm guessing that you're starting this processing from a button click event. Make the method invoked by that click event async. For example:
private async void StartProcessing_Click(object sender, EventArgs e)
{
await Task.Run(() => StartProcessing());
}
There, you've started processing and the UI thread isn't tied up.
The next thing is that, you're right, having the event behave in that cyclical manner is silly. The event is to notify someone that the state has changed, its goal isn't to manage queue policy. The queue should manage queue policy (or if you'd rather not abstract that out, the method that processes requests).
So how would you do that? Well, you've said that SendRequest hands the session object back to the caller. The caller is presumably the one who is orchestrating queue policy and determining whether or not to call SendRequest again.
Have the caller check the session object for validity and decide whether to keep going based on that.
Additionally, I'm unfamiliar with that particular library, but briefly glancing at the documentation it looks like there's also a SendRequestAndWait() method with the same signature and that sounds like it might better meet your needs.
As an example suppose we have this:
public class MyClass
{
public async Task<bool?> MySynchronousNonBlockingFunction()
{
await here ...
return MyDialogResult;
}
}
and caller must call my function as below:
public async void Button_Click()
{
var instance = new MyClass();
var result = await instance.MySynchronousNonBlockingFunction();
if (result == true)
{
some work ...
}
}
But using Task for awaiting as a such, forces you to make your MySynchronousNonBlockingFunction() function async. And as a side effect you must call MyClass.MySynchronousNonBlockingFunction() only inside an async void to be worked as expected.
I think it is not well for the caller. Because a lazy developer in an application development team may call MySynchronousNonBlockingFunction() without await and then application will not works fine. I want handle this async operation in my code internally and not to the caller. To prevent this development mistakes. same as this one:
public void Button_Click()
{
var instance = new MyClass();
var result = instance.MySynchronousNonBlockingFunction();
if (result == true)
{
some work ...
}
}
In fact, i not want freeze the running thread by wait nor actually pause thread so it must be free to process other its works in another call stack again. Witch i want is actually same as the work of await keyword for a Task execution. is there another option to make this use? and what is your solution here to implement await behavior?
I know there is in c# some ways to lock an object full-fanced and force the execution stack to wait. (for example by using Monitor, or Mutex etc). And all the ways that i found in c# are blocking the running thread.
But, How can i implement awaiting manually? Is there another way to achieve this purpose?
In fact, i want pause ui thread from continue executing at a position, and then resume it again to continue execution in later (from CallStack snapshot position). But i not want freeze or actually pause therad so it must be free to process other its works in another call stack again. Witch i want is actually same as the work of await keyword for a Task execution. is there another option to make this use?
That's not how await works, though. await works by returning and then resuming just that method later. In particular, the call stack is not captured.
If you want to mess around with switching thread stacks, then check out fibers. However, there are no .NET bindings for the fiber APIs, and it's quite possible that a lot of .NET code will simply break if you try to use fibers instead of threads. Then there's the whole question of whether a fiber can actually be an STA context for UI elements; I'm really not sure about that one. In short, here be dragons.
and what is your solution here?
Well, a modal dialog - by definition - is supposed to block other dialogs and run a nested message loop.
If you don't want this behavior, then write modeless dialogs instead. I.e., call Show instead of ShowDialog.
GUI window handlers are message-driven state-machines. You must write code that reflects that. That means no, you cannot sanely just wait, and you should not try.
First of all, I've already seen this question, and I (kind of) understand why I'm getting this exception, I would like to know what is the best way to fix it. My code looks somewhat like this (this is a WinRT application):
//Here is my App constructor:
public App()
{
this.InitializeComponent();
this.Suspending += this.OnSuspending;
//Initializing the model
_model = new Model();
_model.LoadData();
}
//the LoadData method looks like this:
public async void LoadData()
{
StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFile file = await folder.GetFileAsync(#"Assets\Data.json");
string data = await FileIO.ReadTextAsync(file);
var dataList = JsonConvert.DeserializeObject<List<MyDataClass>>(data);
// From time to time (pretty rarely, honestly) this line causes the
// "A method was called at an unexpected time" thing:
var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
foreach (var item in dataList)
{
//do some stuff
//<...>
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() => {
//do some stuff in the UI thread
});
}
}
Obviously, having the LoadData method async void is not the best solution. However, as you can see, I have to do some async function calls (to read data from a file) inside of it. Right now I can think of two possible solutions:
Change LoadData to public async Task LoadData() and change it's call in the application constructor to _model.LoadData().GetAwaiter().GetResult(); in order to run it synchronously;
Change LoadData to public void LoadData(), and change all the await calls inside of it to use the awaiter, e.g. StorageFile file = folder.GetFileAsync(#"Assets\Data.json").GetAwaiter().GetResult().
Which of these is a better solution, or, better yet, is there any other proper way to run async code on the application startup? Also, why is the "A method was called at an unexpected time" error happening on the dispatcher line?
Which of these is a better solution
Both of the prospective solutions block - specifically, they block on I/O. Let's think about blocking for a bit, but this time instead of the app's perspective of "I need this data before I can display what I want", consider it from the runtime's perspective.
The runtime absolutely, positively should not ever block the UI. Blocking the UI blocks the user, and that is simply an unacceptable user experience. This is why the entire mobile world is async-first; this comes as a shock to many desktop developers. Desktop apps should be async-first, but mobile apps must be async-first.
So, from the runtime's perspective, when it starts an app, the app must show something. Immediately. Now. I/O is not an option. It doesn't have to be the perfect app home screen, but the app must show something synchronously.
This is why blocking is not going to work. The automated app store code analysis should reject both blocking approaches.
is there any other proper way to run async code on the application startup?
Yes, but the app must compromise. It cannot block the UI while it does its I/O before showing its pretty, full-formed first screen to the user. Some desktop apps can get away with this (even though they shouldn't either), but it's just not an option for mobile apps.
Instead, the app should (synchronously) load and show a "loading..." state. This can be a splash screen, or the actual main screen just with a "loading..." message or spinner in place of the data. This satisfies the runtime's requirements. Of course, before returning, the app should also start the asynchronous operation to retrieve the data, and later update the UI to show what it really wants to show (the regular view complete with the data).
This can be as simple as using an asynchronous event (as #marcinax commented):
protected override async void OnLaunched(...)
{
... // Initialize UI to "Loading" state.
_model = new Model();
await _model.LoadData();
... // Update UI with data in _model.
}
Personally, I prefer to keep all the UI code in the UI layer (not part of Model), so if you have any explicit (non-data-bound) UI initialization to do with the data, it should go after // Update UI.
However, if you find yourself doing this several times in your app (e.g., each window/page needs to load data), then you may prefer an asynchronous data-binding solution like the one described in my MSDN article.
Also, why is the "A method was called at an unexpected time" error happening on the dispatcher line?
I'm not entirely sure, but I suspect the dispatcher was not running yet.
One of the very nice side effects of keeping the UI code out of the model/VM layer is that explicit CoreDispatcher code is no longer necessary. There is always a better solution.
Sorry for the lengthy post, I just want to illustrate my situation as best as possible. Read the items in bold and check the code if you want the quick gist of the issue.
I use ClickOnce to deploy a C# application, and have opted to have my application check for updates manually using the ApplicationDeployment Class rather than letting it do the update checking for me.
The program is a specialized network scanner that searches for network devices made by the company I work for. Once the main window is loaded, a prompt is displayed asking if the user would like to scan the network. If they say Yes, a scan begins which can take a minute or two to complete depending on their network settings; otherwise it just waits for the user to do some action.
One of the last things I do in Form_Load is create a new thread that checks for updates. This had all been working fine for several months through about 12 releases and has suddenly stopped working. I didn't change the update code at all, nor change the sequence of what happens when the app starts.
In staring at the code, I think I see why it is not working correctly and wanted to confirm if what I think is correct. If it is, it begs the question as to why it DID work before - but I'm not too concerned with that either.
Consider the following code:
frmMain.cs
private void Form1_Load(object sender, EventArgs e)
{
// set up ui, load settings etc
Thread t = new Thread(new ParameterizedThreadStart(StartUpdateThread));
t.Start(this);
}
private void StartUpdateThread(object param)
{
IWin32Window owner = param as IWin32Window;
frmAppUpdater.CheckForUpdate(owner);
}
frmAppUpdater.cs
public static void CheckForUpdate(IWin32Window owner)
{
if (ApplicationDeployment.IsNetworkDeployed) {
Console.WriteLine("Going to check for application updates.");
parentWindow = owner;
ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
ad.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);
ad.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(ad_CheckForUpdateProgressChanged);
ad.CheckForUpdateAsync();
// CAN/WILL THE THREAD CREATED IN FORM1_LOAD BE TERMINATED HERE???
}
}
When the CheckForUpdateAsync() callback completes, if no update is available the method call simply returns; if an update IS available, I use a loop to block until 2 things occur: The user has dismissed the "Would you like to scan prompt" AND no scan is currently running.
The loop looks like this, which takes place in ad_CheckForUpdateCompleted:
while (AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) {
System.Threading.Thread.Sleep(5000);
}
I sleep for 5 seconds because I figured this was happening in a separate thread and it has seemed to work well for a while.
My main question about the above code is:
When ad.CheckForUpdateAsync(); is called from CheckForUpdate does the thread I created in Form1_Load terminate (or might it terminate)? I suspect it may because the subsequent Async call causes the method to return, and then start another thread?
The only reason I am confused is because this method WAS working for so long without hanging the application and now all of the sudden it hangs and my best effort at debugging revealed that it was that Sleep call blocking the app.
I'd be happy to post the full code for frmAppUpdater.cs if it would be helpful.
When ad.CheckForUpdateAsync(); is called from CheckForUpdate does
the thread I created in Form1_Load terminate (or might it terminate)?
If the CheckForUpdateAsync() call is asynchronous then yes, the thread will terminate, no it won't otherwise.
If you suspect the Sleep to have caused the application hang then these two variables AppGlobals.ScanInProgress and AppGlobals.ScanPromptVisible are probably always set to true! You should start looking at the code that is setting them to true and see what is going on there.
In order to avoid an application hang, you could introduce a variable to avoid sleeping indefinitely:
int nTrials = 0;
while ((AppGlobals.ScanInProgress || AppGlobals.ScanPromptVisible) && (nTrials < 5)) {
System.Threading.Thread.Sleep(5000);
nTrials++;
}
// Check the results and act accordingly
I personally do not like using Sleep for thread synchronization. .NET offers a bunch of classes that are perfect for thread synchronization, WaitHandle being one of them.
See this post at Asynchronous Delegates Vs Thread/ThreadPool?
your form load method seems to be doing synchronous work. you mention that you are using clickonce deployment. Has the binary location changed after the previous release or has permissions on this resource changed. Looks like the work (checkupdates) in the Thread is never finishing and is never handed back to the form.
as an immediate fix, I would change the Thread approach to Delegate - if you use delegate, then this becomes less of a customer issue (the form will respond to end user) but the underlying problem remains.
as the next step, i would go through http://msdn.microsoft.com/en-us/library/ms229001.aspx and do the troubleshoot