Perhaps the title is worded incorrectly.
I have a "global" Busy Indicator that works great, as long as I don't try to use it when a ChildWindow is open.
I access the "global" Busy Indicator by using a static method in my App.xaml.cs:
BusyIndicator b = (BusyIndicator)App.Current.RootVisual;
if (b != null)
{
b.BusyContent = busyText;
b.IsBusy = true;
}
However, if a ChildWindow is open, the BusyIndicator is always behind it.
I thought that I could set b.Content = VisualTreeHelper.GetOpenPopups().First()
, but that didn't work either.
Does anyone have any tips on having a BusyIndicator on top of open ChildWindows?
Thanks in advance.
UPDATE (SOLUTION)
Dave S sent me on the right track. It was more complicated than I had hoped, but here's my solution.
First, I had to make a full style for the ChildWindow, copying all of the Template style (left some out for post-size reasons):
<Style x:Key="MyChildWindowStyle" TargetType="gs:MyChildWindow">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="gs:MyChildWindow">
<toolkit:BusyIndicator IsBusy="{TemplateBinding IsBusy}" BusyContent="{TemplateBinding BusyContent}" BusyContentTemplate="{StaticResource MyBusyIndicatorDataTemplate}">
<Grid>
<ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</toolkit:BusyIndicator>
</Style>
Then, I created my base class; notice the constructor sets the style. (Errors occurred if I tried to make it abstract.)
public class MyChildWindow : ChildWindow
{
public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register("IsBusy", typeof(bool), typeof(MyChildWindow), null);
public static readonly DependencyProperty BusyContentProperty = DependencyProperty.Register("BusyContent", typeof(object), typeof(MyChildWindow), null);
public bool IsBusy
{
get { return (bool)GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
public object BusyContent
{
get { return GetValue(BusyContentProperty); }
set { SetValue(BusyContentProperty, value); }
}
public MyChildWindow()
{
this.Style = Application.Current.Resources["MyChildWindowStyle"] as Style;
}
}
Make sure to add a new ChildWindow, and change the <controls:ChildWindow to <gs:MyChildWindow (same with the code-behind).
Finally, update the static SetBusyIndicator method:
public static void SetBusyIndicator(string busyText, Uri busyImage)
{
var op = VisualTreeHelper.GetOpenPopups().Where(o => o.Child is MyChildWindow);
if (op.Any())
{
var bidc = new MyBusyIndicatorDataContext(busyText, busyImage);
foreach (System.Windows.Controls.Primitives.Popup p in op)
{
var c = p.Child as MyChildWindow;
c.BusyContent = bidc;
c.IsBusy = true;
}
}
else
{
BusyIndicator b = Current.RootVisual as BusyIndicator;
if (b != null)
{
b.BusyContent = new MyBusyIndicatorDataContext(busyText, busyImage);
b.IsBusy = true;
}
}
}
I'm not sure this is the most efficient, but it does seem to work nicely.
You don't have to subclass ChildWindow to be able to use BusyIndicator over ChildWindows. I am using following solution:
1-Define Global ContentTemplate for all ChildWindow Controls. Bind IsBusy property to "IsBusy" of ChildWindow's datacontext.
2- Define a singleton class which is ready during silverlight application is running. I picked App class for this. Implement INotifyPropertyChanged interface to auto refresh all IsBusy binders. Implement IsBusy property. Implement ShowBusyIndicator and HideBusyIndicator methods. In ShowBusyIndicator method iterate all open ChildWindows and update their DataContexts.
As you've got your application root visual set to the busy spinner you will not be able to change the Z-Index so it is higher than the ChildWindow. Your best bet would be to extend the ChildWindow control and add a busy spinner into it and then set IsBusy on the ChildWindow rather the root visual when you have windows open.
Hope that helps.