Multiplethreading MVVM update value when Current Dispatcher is working - wpf

I've problem with update value in window, which is open via Show() method not ShowDialog() method. I use MVVM and use binding like:
Value="{Binding Path=MainProgressValue, UpdateSourceTrigger=PropertyChanged}"
In my property I use INotifyPropertyChanged for notify UI.
It worked fine, but now I open new window
window.DataContext = context;
if (owner != null)
window.Owner = owner;
resultHandler = new ViewModelBaseClass.ResultHandler(context_RequestClosing);
getDialogResultHandler = new ViewModelBaseClass.GetDialogResultHandler(context_GetDialogResultAction);
context.RequestClosing += resultHandler;
context.GetDialogResult += getDialogResultHandler;
window.Show();
There is progress bar. The window is shown and main thread continue with proceed program. But when DataContext call RaisePropertyChanged, the progress bar doesn't update. Is it possible that the window with progress bar uses another thread than the main thread?
How to update this value?

My guess based on your description is that you are expecting the UI to refresh while the main application thread is busy doing something. The main application thread is the UI thread so if this is the case you UI thread is blocked.
What you need to do is move the "program" portion that is doing the loading etc. and updating the progress value off into a worker thread (See ThreadPool) and when you want to signal the UI to refresh use the Dispatcher.BeginInvolke() example you found. This will execute your refresh code on the main UI thread.

Related

How to set busy cursor for slow WPF controls

There appears to be a lot of resources on showing the busy cursor.
But all the solutions I've managed to find relies on setting the cursor via the view model. (i.e, IsBusy property, disposable WaitCursor).
These methods work well when I know when my data binding/view models will be long-running.
But I don't know how to do this automatically for cases where the bottleneck is the actual WPF user control itself?
For example:
Loading a control is initially lag-free. But once a 3rd party control is used, the control exhibits a 500-ms lag every time it loads.
The binding itself is fast, hence, adding a waitcursor/IsBusy in the view model is useless because it wouldn't know when the control (or any of its logical/visual children) has finished rendering. Nor should it know, as the view model should not be affected by the view's implementation.
Is it possible for the application to automatically set the cursor to busy when one or more WPF controls is busy/slow?
You may need something like this,
var busytimer = new DispatcherTimer(
TimeSpan.FromSeconds(1),
DispatcherPriority.Normal,
delegate
{
Process application = null;
foreach (var process in Process.GetProcesses())
{
if (process.ProcessName == "Your process name")
{
application = process;
break;
}
}
if (!application.Responding)
{
this.Cursor = Cursors.Wait;
}
else
{
this.Cursor = Cursors.Arrow;
}
},
Application.Current.Dispatcher);
Is it possible for the application to automatically set the cursor to busy when one or more WPF controls is busy/slow?
Not really. If your UI thread is blocking, you won't be able to update the cursor until it becomes unblocked anyway, which defeats the purpose.
The binding itself is fast, hence, adding a waitcursor/IsBusy in the view model is useless because it wouldn't know when the control (or any of its logical/visual children) has finished rendering. Nor should it know, as the view model should not be affected by the view's implementation.
If you go with the IDisposable wait cursor solution, you could try scheduling the Dispose() call to occur after the next layout pass:
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Loaded,
new Action(() => waitCursor.Dispose()));

WPF application login window not on top

I'm using Prism's MefBootstrapper to initialize my WPF application, as part of this process the Shell window is being initialized.
After Running the MefBootstrapper's Run() method, I'm displaying a login window which connects to a server and in case of a successful connection, the Shell is loaded (from main UI thread).
This login window is running on a new dedicated UI thread, in order not to freeze the progress-bar in this process (connection to the server and especially the Shell loading).
Unfortunately, the login window is not showed on the top and not Focused (even when I'm using: Activate(), TopMost=true, Focus() ).
//UI mode - a new UI thread is initialized
var uiThread = new Thread(() =>
{
var loginWindow = new LoginWindow();
loginWindow.Show();
loginWindow.Activate();
loginWindow.Topmost = true;
loginWindow.Topmost = false;
loginWindow.Focus();
System.Windows.Threading.Dispatcher.Run();
});
uiThread.SetApartmentState(ApartmentState.STA);
uiThread.IsBackground = true;
uiThread.Start();
How can I solve this issue?
Try uiThread.IsBackground = false;
Can you send new instance of LoginWindow to the thread?
uiThread.Start(new LoginWindow());
and then use the loginWindow parameter in the Thread delegate to Show.
I guess that would cause the window to render in the current dispatcher context and would render it on the foreground.
I would create the loginWindow before the ShellWindow is created, just before the end of ConfigureContainer().
That way you won't unnecessarily create views - viewmodels in your regions.
Note, it is important that you don't Close the window before you have shown your ShellWindow (i.e. hide it on successful login) or else the Application will close too.

show Loading animation in wpf

I am trying to show a loading animation when a page is taking time to load. I am loading multiple/several user controls depending on user request using Thread. I have tried the following ways
this.Dispatcher.BeginInvoke(new Action(LoadSecondPageData), DispatcherPriority.Background);
when I am using this it is making my Loading animation freeze until the page loads
I also tried BackgroundWorker concept Loading animation is working here, but it is not allowing to load the usercontrols and giving an error.
Error: "The calling thread must be STA, because many UI components require this."
You need to start the animation on the main UI Thread using Dispatcher.BeginInvoke, but any loading of data should happen on a background thread so that the animation doesn't freeze.
When the data is loaded, any final updates that effect dependency properties need to be marshalled onto the UI thread using Dispatcher.BeginInvoke once more.
I also tried BackgroundWorker concept Loading animation is working here, but it is not allowing to load the usercontrols and giving an error.
This is by design, you're not allowed to touch anything on the UI side in your background thread, as it will not be STA. Instead, bind your progress indicator to properties that the thread could modify, and then the progress indicator will get the update via the INotifyPropertyChanged event.
For example, if you had a ProgressBar bound to ProgressPercentage, or an indeterminate busy indicator bound to IsBusy:
In XAML:
<ProgressBar x:Name="StatusBar"
Maximum="1" Value="{Binding ProgressPercentage}" />
In Code:
using (var backgroundWorker = new BackgroundWorker())
{
backgroundWorker.DoWork += (s, ex) =>
{
IsBusy = true;
StatusText = "Pretending to do something...";
for (int i = 0; i < 100; i++)
{
ProgressPercentage = (i + 1)/100.0D;
Thread.Sleep(100);
}
};
backgroundWorker.RunWorkerCompleted += (s, ex) =>
{
IsBusy = false;
StatusText = "Export Complete.";
};
backgroundWorker.RunWorkerAsync();
}
The background thread will do its work, the UI thread will not block while waiting, and your progress indicator will update as it goes.

WPF Work-In-Progress animation not displaying for data binding updates

I have a helper class I've written which can be used to run a long running task on my GUI. What it does is use styles to display a "working" animation and fades out the content so while the task is running, the user can see that something is in progress.
My problem is that when the long running task completes, it fades the content back in and hides the working animation - which is what it should do, but because I am using MVVM and primarily data binding for all my content display, the updates to the GUI components happen separately to the long running task. ie the data binding OnPropertyChanged("") events fire and then these are picked up by the GUI thread AFTER the long running task completes. But the problem is the Worker Animation closes when the long running task completes, but BEFORE the data bindings update.
So the end result is you get the worker animation displaying as expected while the task runs, but the data binding update takes a good 4-5 seconds or even longer for large datasets for all the tree data and during this time, the application is not in "working animation mode" and just freezes.
Is there a way I can have my worker animation continue to run not only for the Long running Method, but for the associated data binding updates from OnPropertyChanged as well?
Consider using BusyIndicator from Extended WPF toolkit. It should provide functionality you described. It has IsBusy property which you can bind to property in your ViewModel and set it to False after all work is done.
You can always change the style of BusyIndicator same way as you do with other controls. In my solutions I always use this control along with BackgroundWorker class from System.ComponentModel and I usually set IsBusy=false at the end of RunWorkerCompleted
private void LongRunningMethod()
{
this.IsBusy = true;
var worker = new BackgroundWorker();
worker.DoWork += this.LongMethodDoWork;
worker.RunWorkerCompleted += this.RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void LongMethodDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
...
}
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
...
this.IsBusy = false;
}
Thanks all for the answers. I've actually come across a solution that may be a bit controversial as some would construe it is a little bit of a hack, but it does exactly what I want it to do and there seems to be no other way to do it, so to me that is a code solution, not a hack.
I'm using the WPFBackgroundProgressIndicator open source project I downloaded from codeproject (I think) which has the option to show the busy indicator in the main content with or without a fade out, or as a popup and it runs as a background thread which is ideal and why I chose it.
The problem was that when you run a long running method, the code execution completes synchronously but all the binding OnPropertyChanged("") updates run asychronously and queue on the Dispatcher thread, so your work method completes before the WPF controls have a chance to call the Getters of the dependency properties, to retrieve the new value. What you need to do is effectively "block" until all the Dispatcher events have completed and that is why not everyone will like this solution as it "blocks", but then that is exactly what I am trying to do. I WANT to block the application until the full update has completed as I dont want the user to be able to do anything visually while data is still rendering, so that is my requirement. Clean blocking is preferable to messy interaction.
So the solution, believe it or not, is a single line of code just after the work method call. It is as follows.
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);
Which as you can see effectively queues a new task on the Dispatcher thread and blocks current code execution until it finishes, but as you give it the lowest priority, this call will wait until all OTHER dispatcher execution finishes, ie all rendering completes. Once render is complete, this line will be executed and you will exit with all rendering complete. The full method I have used it in context is below. I welcome your thoughts and discussion on this approach.
public void LongRunningTaskWithFade(BusyDecorator busy, Action longTask)
{
if (loading) return;
loading = true;
busy.FadeTime = TimeSpan.Zero;
busy.IsBusyIndicatorShowing = true;
// in order for setting the opacity to take effect, you have to delay the task slightly to ensure WPF has time to process the updated visual
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
longTask();
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);
}
finally
{
HideBusyDisplay(busy);
}
}), DispatcherPriority.Background);
}

performing database operations in the background in WPF application?

In my WPF application I need to perform database operattions in the background to make the UI more responsive.
I'm making use of the BackgroungWorker class, but since it operates on different thread than that of UI, i can't pass the parameters to the database queries.These values comes from the UI controls.
Could anyone please help me with this problem or suggest some other way to do database operations,at the same time making UI responsive.
Thank You
Instead of using BackgroungWorker class you could work with Dispatcher.BeginInvoke method. In fact as specified by MSDN:
BeginInvoke is asynchronous; therefore, control returns immediately to the calling object after it is called.
In WPF, only the thread that created a DispatcherObject may access that object. For example, a background thread that is spun off from the main UI thread cannot update the contents of a Button that was created on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous. The operation is added to the event queue of the Dispatcher at the specified DispatcherPriority.
Here a good article that explains how to work with Dispatcher class.
I think the BackgroundWorker is the correct tool for the job. When you create a BackgroundWorker you specify an event handler for the DoWork event. The DoWorkEventArgs object has a property on it called Arguments which is the object passed in when you start the BackgroundWorker by calling RunWorkerAsync. You may need to create a helper class to handle the parameters you need to pass, but that should be quite easy. Something like
Helper Class:
public class WorkerArgs
{
public string Arg1 {get;set;}
public object Arg2 {get;set;}
public int Arg3 {get;set;}
}
Background Worker:
BackgroundWorker worker = new BackgroundWorker();
// Hook up DoWork event handler
worker.DoWork += (sender, e) => {
WorkerArgs args = e.Arguments as WorkerArgs;
// ... Do the rest of your background work
};
// Create arguments to pass to BackgroundWorker
WorkerArgs myWorkerArgs = new WorkerArgs {Arg1 = "Foo", Arg2 = new Object(), Arg3 = 123 };
// Start BackgroundWorker with arguments
worker.RunWorkerAsync(myWorkerArgs);
In your case, you would populate the helper class object with values from your UI controls.

Resources