I'm developing a WPF desktop application in c# 4.0 which has to handle a lot of long-running operations (loading data from the DB, calculating simulations, optimizing routes, etc.).
When these long-running operations run in the background I want to show a Please-Wait dialog. When the Please-Wait dialog is shown the application should be locked, but to just disable the application window isn't a good idea because all the DataGrids would lose their status (SelectedItem
).
What I have so far works but there are some problems: A new WaitXUI is created using the Create-factory method. The Create method expects caption text and a refernce to the host control that should be locked. The Create method sets the StartupLocation of the window, the caption text and the host to lock:
WaitXUI wait = WaitXUI.Create("Simulation running...", this);
wait.ShowDialog(new Action(() =>
{
// long running operation
}));
With the overloaded ShowDialog method the WaitXUI can then be displayed. The ShowDialog overload does expect an Action which wraps the long running operation.
In the ShowDialog overload I just start the Action in its own thread and then disable the host control (set Opacity to 0.5 and set IsEnabled to false) and call ShowDialog of the base class.
public bool? ShowDialog(Action action)
{
bool? result = true;
// start a new thread to start the submitted action
Thread t = new Thread(new ThreadStart(delegate()
{
// start the submitted action
try
{
Dispatcher.UnhandledException += Dispatcher_UnhandledException;
Dispatcher.Invoke(DispatcherPriority.Normal, action);
}
catch (Exception ex)
{
throw ex;
}
finally
{
// close the window
Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
this.DoClose();
}
}));
t.Start();
if (t.ThreadState != ThreadState.Stopped)
{
result = this.ShowDialog();
}
return result;
}
private new bool? ShowDialog()
{
DisableHost();
this.Topmost = true;
return base.ShowDialog();
}
private void DisableHost()
{
if (host != null)
{
host.Dispatcher.Invoke(new Action(delegate()
{
this.Width = host.Width - 20;
host.Cursor = Cursors.Wait;
host.IsEnabled = false;
host.Opacity = 0.5;
}));
}
}
Here are the problems with this:
These are the main problems which come to my mind at the moment. How can this concept be improved, or what other methods can be employed to address this problem?
Thanks in advance!
A little lateral thinking always helps when developing WPF applications. You can fulfil your requirements easily with just a Grid
, a Rectangle
, a bool
property (which you could already have) and a BooleanToVisibilityConverter
and you won't have to disable any controls.
The idea is simple. Add a white Rectangle
in front of your view content with its Opacity
property set between 0.5
and around 0.75
. Data bind its Visibility
property to the bool
property in your view model or code behind and plug in the BooleanToVisibilityConverter
:
<Grid>
<Grid>
<!--Put your main content here-->
</Grid>
<Rectangle Fill="White" Opacity="0.7" Visibility="{Binding IsWaiting,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<!--You could add a 'Please Wait' TextBlock here-->
</Grid>
Now when you want to disable the controls, you just set the bool
property to true
and the Rectangle
will make the UI appear faded:
IsWaiting = true;
Don't really need to create own implementation, I think it's redundant.
take a look into already created component, like BusyIndicator, for similar needs. which is vital and effective. .
more info from codeplex
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With