Silverlight BusyIndicator: более высокий Z-индекс, чем у всех дочерних окон
Возможно, название сформулировано неверно.
У меня есть "глобальный" индикатор занятости, который прекрасно работает, пока я не пытаюсь использовать его, когда открыто ChildWindow.
Я получаю доступ к "глобальному" индикатору занятости, используя статический метод в моем App.xaml.cs:
BusyIndicator b = (BusyIndicator)App.Current.RootVisual;
if (b != null)
{
b.BusyContent = busyText;
b.IsBusy = true;
}
Однако, если ChildWindow открыто, Busy Indicator всегда стоит за ним.
Я думал, что я мог бы установить b.Content = VisualTreeHelper.GetOpenPopups().First()
, но это тоже не сработало.
У кого-нибудь есть какие-либо советы по использованию Busy Indicator поверх открытых ChildWindows?
Заранее спасибо.
ОБНОВЛЕНИЕ (РЕШЕНИЕ)
Дэйв С. отправил меня на правильный путь. Это было сложнее, чем я надеялся, но вот мое решение.
Во-первых, мне нужно было сделать полный стиль для ChildWindow, скопировав весь стиль Template (оставив некоторые из них по соображениям размера пост-размера):
<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>
Затем я создал свой базовый класс; обратите внимание, конструктор устанавливает стиль. (Произошли ошибки, если я попытался сделать это абстрактным.)
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;
}
}
Убедитесь, что вы добавили новое ChildWindow и измените значение Наконец, обновите статический метод SetBusyIndicator: Я не уверен, что это наиболее эффективно, но, похоже, работает хорошо.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;
}
}
}
2 ответа
Так как корневая визуализация вашего приложения установлена на занятое вращение, вы не сможете изменить Z-индекс, поэтому он выше, чем ChildWindow. Лучше всего было бы расширить элемент управления ChildWindow и добавить в него занятый счетчик, а затем установить IsBusy в ChildWindow, а не корневой визуальный элемент, когда у вас открыты окна.
Надеюсь, это поможет.
Вам не нужно создавать подкласс ChildWindow, чтобы иметь возможность использовать BusyIndicator поверх ChildWindows. Я использую следующее решение:
1-Определить глобальный ContentTemplate для всех элементов управления ChildWindow. Привязать свойство IsBusy к "IsBusy" из текстового контекста ChildWindow.
<Style TargetType="sdk:ChildWindow">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<toolkit:BusyIndicator IsBusy="{Binding IsBusy}">
<ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</toolkit:BusyIndicator>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
2. Определите одноэлементный класс, который готов во время работы приложения Silverlight. Я выбрал класс приложения для этого. Реализуйте интерфейс INotifyPropertyChanged для автоматического обновления всех связывателей IsBusy. Реализуйте свойство IsBusy. Реализуйте методы ShowBusyIndicator и HideBusyIndicator. В методе ShowBusyIndicator выполните итерацию всех открытых ChildWindows и обновите их DataContexts.
public class App : Application, INotifyPropertyChanged
{
public static BusyIndicator GlobalBusyIndicator { get; private set; }
private bool _isBusy;
public bool IsBusy
{
get
{
return _isBusy;
}
set
{
_isBusy = value;
RaisePropertyChanged(new PropertyChangedEventArgs("IsBusy"));
}
}
public static void ShowBusyIndicator()
{
var popups = VisualTreeHelper.GetOpenPopups();
foreach (var p in popups)
{
ChildWindow cw = p.Child as ChildWindow;
if (cw != null)
cw.DataContext = App.Current;
}
(Current as App).IsBusy = true;
GlobalBusyIndicator.IsBusy = true;
}
public static void HideBusyIndicator()
{
(Current as App).IsBusy = false;
GlobalBusyIndicator.IsBusy = false;
}
private void Application_Startup(object sender, StartupEventArgs e)
{
string baseurl = Host.Source.AbsoluteUri;
BaseUrl = baseurl.Substring(0, baseurl.IndexOf("ClientBin"));
GlobalBusyIndicator = new BusyIndicator();
GlobalBusyIndicator.HorizontalAlignment = HorizontalAlignment.Stretch;
GlobalBusyIndicator.VerticalAlignment = VerticalAlignment.Stretch;
GlobalBusyIndicator.Content = new Shell();
this.RootVisual = GlobalBusyIndicator;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
}