Say I have a command's execute method that looks like this:
private void Execute()
{
// Bound to a wait indicator in the UI
Searching = true;
// Do some long running process
Thread.Sleep(2000);
Searching = false;
}
When Searching is set to True, the UI element that it is bound to will not update (even though Searching sends the OnPropertyChanged call).
However, once the Thread.Sleep finishes, then the UI then processes my change and shows the wait indicator that Searching is bound to.
Now, I know the conventional wisdom is to make the call to the long running process (Thread.Sleep) be async.
But suppose I am not using the Async libraries, is there a way to instruct WPF to perform the binding on Searching right now?
Something like this:
private void Execute()
{
// Bound to a wait indicator in the UI
Searching = true;
// MADE UP CODE
Binding.UpdateBindingNow("Searching");
// END MADE UP CODE
// Do some long running process
Thread.Sleep(2000);
Searching = false;
}
UPDATE: What I have tried:
Using Dispatcher to try sending the command to the UI Separately.
I also tried the Dispatcher with a high priority.
You need to push your work into a background thread. The bindings won't update until the UI thread can process messages, which won't happen until your operation completes.
Async is one approach, but a more classic approach would be to just use BackgroundWorker to do this, which is supported in all versions of WPF.
If you're using .NET 4, you could do this via the TPL, as well:
private void Execute()
{
// Bound to a wait indicator in the UI
Searching = true;
Task.Factory.StartNew( () => {
// Do long running work...
}).ContinueWith(t =>
{
// You can do work here, including touching UI controls/collections/etc
Searching = false;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
I agree with others that moving the long-running process to a background/asynch operation is the best way to go. Both because your UI doesn't freeze for the user and also because whatever you do (refresh your binding, whatever) won't actually be reflected in the UI while the long-running process is working because the UI thread will be blocked.
That said, your question is can you force the binding to evaluate/refresh from code, and the answer is yes. You accomplish this by calling UpdateTarget on the BindingExpression like this:
labelTextBlock.GetBindingExpression(TextBlock.TextProperty).UpdateTarget();
There is also an UpdateSource method on the BindingExpression that can be used in much the same way, only impacting the source rather than target.
Again, if your UI thread is blocked, it may not accomplish what you're hoping for, but this is how you would force the binding to re-evaluate.
Related
I have a WinForm application and I am trying to update a progressbar in a parallel loop. Here is the snippet of my code:
Parallel.ForEach(files, (file, state) =>
{
//Intialization of parameters
//do cpu-intensive task
DoWork();
UpdateProgress();
});
int counter = 0;
private object updateLock = new object();
void UpdateProgress()
{
lock (updateLock)
{
counter++;
if (progressBar1.InvokeRequired)
{
progressBar1.Invoke(() => { progressBar1.SetProgress(counter); });
}
else
{
progressBar1.SetProgress(counter);
}
}
}
To get an instant update on progressbar animation I use the SetProgress.
public static void SetProgress(this ProgressBar bar, int value)
{
if (value == bar.Maximum)
{
bar.Maximum = value + 1;
bar.Value = value + 1;
bar.Maximum = value;
}
else
{
bar.Value = value + 1;
}
bar.Value = value;
}
The whole process seems to work fine, but I have a problem with the way progress bar is updated. Randomly I see the progress animations is set back and forth, say e.g go to 33/150, then to 31/150 and then to 32/150. Although I used a synchonization lock object to update progress on each step accordingly, it seems the messages in Main UI Thread are not processed in order or there is something wrong with the code.
Any ideas what might be the issue?
Thanks in advance.
[UPDATE]
The problem is related with how Parallel.ForEach works. You may think that it uses only background threads to do the work, but it actually uses the current thread too. In other words during the execution of the Parallel.ForEach, the current thread plays the role of a worker thread. In your case the current thread is the UI thread. The condition if (progressBar1.InvokeRequired) evaluates to true for the background threads involved in the operation, and false for the UI thread.
The background threads are calling the progressBar1.Invoke method in your example. Unlike the BeginInvoke, the Invoke is a blocking method, and will return only after the UI thread has processed the supplied delegate. Since the UI thread is busy processing its own partition of the files collection, the Invoke will block, so all background threads will get stuck, and the only thread that will continue making progress will be the UI thread. At the end the UI thread will have to wait for the other threads to deliver the result of the single file they received initially for processing, which they won't be able to do, so the Parallel.ForEach will deadlock. At least this is the expected outcome of the code you posted. Since you are not observing a deadlock, my guess is that there is some line of code missing in your example (a call to Application.DoEvents maybe?) that resolves the deadlock situation.
The easiest way to fix this unpleasant situation is by preventing the UI from becoming a worker thread. Just use the Task.Run method, to offload the whole parallel processing to a ThreadPool thread:
await Task.Run(() =>
{
Parallel.ForEach(//...
});
You will also have to mark your event handler with the async keyword, otherwise the compiler will not permit the usage of the nifty await operator.
After applying this fix, you may want to make your code more elegant by removing all this ugly InvokeRequired/Invoke stuff, and replacing it with a modern Progress object. This would also make trivially easy to seperate the files-processing logic from the UI-related logic, if you find it desirable from an architectural perspective. You can read this article if you want to learn how to use the Progress class.
I've used Visual Studio 2013 to build a C# application with a single form, and the application has two routines that update the screen. The routines that update the screen need to run on the main thread, so my own threads (which don't interact with the screen) call the BeginInvoke method on the main form when updates are required. However, something is happening somewhere in the application with the result that the two update routines stop executing. I've put logging into the app to track the calls to BeginInvoke and the execution of the update routines, and I can see that when this problem occurs, the BeginInvoke calls are made, but then nothing. When this happens, the whole application seems to freeze. I can't think of what might be causing this. How can I debug this? Is there any way of looking at what's queued to run on the main thread? When I run in debug and break into the application, all threads look normal, and the main thread doesn't appear to be doing anything, so why isn't it processing my pending update tasks?
The Control.BeginInvoke() adds the delegate to an internal thread-safe queue. And posts a message to the UI thread to tell it to go have a look in that queue. The message loop inside Application.Run() gets that message and goes about emptying the queue again, executing the delegates.
So if you don't see this happening then the most obvious reason is that the UI thread isn't inside the Application.Run() loop. A standard mistake you could make is waiting for the thread to complete for example. Very likely to cause deadlock. Never wait, if you need to run code after the thread completes then consider BackgroundWorker's RunWorkerCompleted event or TaskScheduler.FromCurrentSynchronizationContext().
The not-so-obvious failure mode of not seeing anything happening is that you are calling BeginInvoke() far too often. If you do this more than ~1000 times per second, give or take, then you'll flood that internal queue with too many delegates. The UI thread will actually be busy emptying that queue but can never catch up, always finding yet another delegate in the queue after executing one. It goes catatonic when this happens, not taking care of its normal duties anymore. Like responding to input and painting the windows. No fix for this, other than limiting the rate at which you call BeginInvoke(). Do keep the target in mind, you only have to do it as often as the user's eyes can perceive. Updating the UI at a rate more then 25 times per second is just wasted effort.
This might be due to the two update routines attempting to update the UI at the same time. I've seen strange UI behaviour, e.g. partially updated controls, when many UI updates occur in a short space of time when triggered by multiple interleaved events. The two routines are different routines, yes?
A possible way to solve this is to use asynchronous delegate invocation on the UI thread. In the code below I've assumed that your UI is a WinForms Form, and I've named the two routines UpdateA and UpdateB.
private bool isUpdating;
public delegate void UpdateDelegate();
private void UpdateA()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateA));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for A
}
finally
{
isUpdating = false;
}
}
}
private void UpdateB()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateB));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for B
}
finally
{
isUpdating = false;
}
}
}
By the way, I didn't use lock above to synchronise access to flag isUpdating, on the assumption that both UpdateA and UpdateB execute on the UI thread. They are invoked asynchronously by the worker threads via BeginInvoke.
I know this has been asked before, but I don't think these solutions are flexible. The DocumentCompleted event should be used to determine when the load has completed, not as a method for performing work. If you need to perform several different tasks that each have to navigate several times, placing the logic in the DocumentCompleted event turns it into a messy switch/case router that is hard to read and maintain.
You need something that can actually wait during your method performing navigation so you can continue your task in the method you are already in. My first though is an actual Wait() method.
I would think something like this is close:
void WaitForLoad()
{
isLoading = true;
while (isLoading)
{
if (Application.Current == null) break;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, (DispatcherOperationCallback)delegate(object unused) { return null; }, null);
}
}
And set Isloading to false in the DocumentCompleted event.
You should be able to just call this method after whatever action will cause a pageload. It works, it has some issues.
1) it sends the CPU usage for the app up to 35% until the page has loaded, even if nothing else is happening.
2) if the application tries to close while its running, the loop will keep running and leave the app open with no windows, hence the need for the break when the app is null.
Can this be fixed, or am I coming at this all the wrong way?
Edit: I tried implementing the ManualResetEvent solution below, but it led to several other issues that I am not sure can be resolved without creating a messier situation than the one above. Since the WebBrowser is on the UI, locking the thread stop the entire app. If the work is done on the background thread it can be locked, but then accessing the WebBrowser becomes very difficult.
In your situation, it sounds like you want a specific thread to block while waiting for the document to load. In that case, you would do something like this:
protected ManualResetEvent _resetEvent = new ManualResetEvent(false);
public void WaitingThread()
{
_resetEvent.WaitOne();
// Do stuff after the web browser completes.
}
public void LoadWebPage()
{
webBrowser.Navigate(new Uri(url));
webBrowser.DocumentCompleted = (s, e) => { _resetEvent.Set(); };
}
Basically, when the document completes, you signal the event and any threads waiting on the event unblock and continue executing.
I noticed that you use Dispatcher.CurrentDispatcher.Invoke this is good for calling your method that somehow updates UI from another thread. But from code provided, I don't see any code in other thread then UI. So
Run that code on another thread.
On the close event of your application you can make isLoading=false; And more, if the method invoked is kind of long running stuff insert
if(!isLoading)
return;
//or in some other app suitable way break an execution
EDIT:
Even better way to handle this in multithreading, then just simply relay on boolean variable, is using some Synchonization object
I am trying to reuse a UserControl and also borrow some logic that keeps track of progress. I'll try and simplify things. MyWindow.xaml includes a MyUserControl. MyUserControl has its own progress indicator (Formatting in progress..., Copying files..., etc.) and I'd like to mirror this progress somewhere in the MyWindow form. But, the user control has some logic I don't quite understand. I've read and read but I still don't understand the Dispatcher. Here's a summary of the logic in the user control that updates the progress.
this.Dispatcher.Invoke(DispatcherPriority.Input, (Action)(() =>
{
DAProgressIndicator = InfiniteProgress.AddNewInstanceToControl(StatusGrid, new SolidColorBrush(new Color() { A = 170, R = 128, G = 128, B = 128 }), string.Empty);
DAProgressIndicator.Message = MediaCardAdminRes.ActivatingCard;
ActivateInProgress = true;
}));
I thought I'd be smart and add an event to MyUserControl that would be called in the ActivateInProgress property set logic.
public bool ActivateInProgress
{
get
{
return _activateInProgress;
}
set
{
_activateInProgress = value;
if (ActivateInProgressHandler != null)
{
ActivateInProgressHandler(value);
}
}
}
I'm setting the ActivateInProgressHandler within the MyWindow constructor to the following method that sets the view model property that is used for the window's own progress indicator.
private void SetActivation(bool activateInProgress)
{
viewModel.ActivationInProgress = activateInProgress;
}
However, the window's progress indicator never changes. So, I'm convinced that the Dispatcher.Invoke is doing something that I don't understand. If I put a message box inside the SetActivation method, the thread blocks and the window's progress indicator is updated. I understand basic threads but this whole Dispatcher thing is new to me. What am I missing?
UPDATE: It seems to be working now. It turns out the progress was being updated so fast that it never got shown on the screen. But, I still would like to understand why the Dispatcher.Invoke was done (this was existing code that I didn't write). Why aren't the action contents done in line with the rest of the *.xaml.cs code?
Your last paragraph mentions threads twice, which raises the possibility that there are one or more background threads. But since you didn't mention what threads exist in the application, how they are created, how they interact, etc, I'll assume for the moment there is only one thread.
If the UI thread is the only thread, the problem is obvious: Your UI thread is busy running the task in progress, and doesn't take time to render the updated UI. If that's the problem, this will probably fix it:
viewModel.ActivationInProgress = activateInProgress;
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
new Action(() => {}));
The BeginInvoke forces all Dispatcher operations above input priority to complete before the current thread continues.
The Dispatcher works on a queue. So it could be that the UI thread is blocking. You add more work in the queue via the Dispatcher but it will never get executed because the UI thread is blocking.
Maybe try this:
DispatcherFrame _frame = new DispatcherFrame();
Dispatcher.PushFrame(_frame);
This will put your work infront of the work already on the queue. So the UI thread will do the work and then block again.
I am just working on my first GUI application on Windows.
I have a WPF GUI to a small C# utility which copies files. When the button is clicked to copy, I obviously don't want the GUI to hang. So, I fire off a new thread to run the method which copies the files. I assume I'm on track so far and there's no "better" way of doing it in C#?
Now, I have a ProgressBar which I want to appear filled when the thread is done. (It's fine running as indeterminate for now). How do I check when the copying is done?
So, so far I have:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
});
t.Start();
PBar.IsIndeterminate = true;
And I want something after that that works like:
if (t.Done)
{
PBar.Value = 100;
}
Have a look at the BackgroundWorker class. It supports events like RunWorkerCompleted or ProgressChanged.
Have a look here, too (this is about threading in general + backgroundworker, again).
As already stated, consider the use of the BackgroundWorker class. It was designed for these situations and exposes events suited for what you are trying to accomplish.
Use the ProgressChangedevent to report progress incrementally and the RunWorkerCompleted for when the task finishes. Check the MSDN page for code samples.
Wrap the if (t.Done) block in its own method. Invoke this method from the end of your worker thread.
Also, you might want to give the worker thread a name to make it easier to spot in the debugger.
You need a callback method. This should get you started. It uses an AsyncCallback, which is the best way to tackle this type of issue.
I just looked up an example I've been using for a project and stripped out the code specific to my app:
System.Windows.Forms.MethodInvoker mi = new System.Windows.Forms.MethodInvoker(delegate()
{
// Do your file copy here
});
AsyncCallback ascb = new AsyncCallback(delegate(IAsyncResult ar)
{
this.Dispatcher.Invoke(new ThreadStart(delegate (){
// set progressbar value to 100 here
}), null);
});
mi.BeginInvoke(ascb, null);
The quick and easy hack would be to just update the UI at the end of your anonymous method in your thread. Obviously you can't update it directly, but you can use Dispatcher.Invoke:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
Dispatcher.Invoke(new Action(()=>{PBar.Value = 100;}),null);
});
t.Start();
As a general Windows programming principal, you have to make calls to update the UI from the UI thread (the one that is processing messages through a message pump).
In Windows Forms, the way that this was done was through the implementation of the ISynchronizeInvoke interface on the Control class, primarily through the implementation of the Invoke method.
With the release of .NET 2.0, it was realized that a better mechanism was needed to marshal calls into the correct context. That's where the SynchronizationContext comes in.
This class abstracts the interface you would use for marshaling calls to different contexts, allowing for specific implementations depending on the context.
So whether or not Windows Forms is the environment, or WPF, one call can be made in the same way across those contexts with the same effect (marshaling the call).
In your particular case, because you are using a closure (anonymous method), you can take advantage of the fact that a SynchronizationContext is available to you (through the static Current property) at the invocation site of the Thread to provide the mechanism to call back to the UI thread from your background thread:
// Get the synchronization context.
// This is in the UI thread.
SynchronizationContext sc = SynchronizationContext.Current;
// Create the thread, but use the SynchronizationContext
// in the closure to marshal the call back.
Thread t = new Thread(delegate()
{
// Do your work.
po.Organise(inputPath, outputPath, recursive);
// Call back using the SynchronizationContext.
// Can call the Post method if you don't care
// about waiting for the result.
sc.Send(delegate()
{
// Fill the progress bar.
PBar.Value = 100;
});
});
// Make the progress bar indeterminate.
PBar.IsIndeterminate = true;
// Start the thread.
t.Start();
Note, if you don't care about waiting for the result of the call back to the UI thread, you can make a call to the Post method instead, which will dispatch the call to the UI thread without waiting for that call to complete.