Silverlight BusyIndicator :比所有 ChildWindows 更高的 Z 索引
也许标题措辞不正确。
我有一个“全局”忙碌指示器,只要我在子窗口打开时不尝试使用它,它就可以很好地工作。
我通过在 App.xaml.cs 中使用静态方法来访问“全局”Busy Indicator:
BusyIndicator b = (BusyIndicator)App.Current.RootVisual;
if (b != null)
{
b.BusyContent = busyText;
b.IsBusy = true;
}
但是,如果 ChildWindow 打开,则 BusyIndicator 始终位于其后面。
我认为我可以设置 b.Content = VisualTreeHelper.GetOpenPopups().First(),但这也不起作用。
有人对在打开的 ChildWindows 之上添加 BusyIndicator 有什么建议吗?
提前致谢。
更新(解决方案)
Dave S 让我走上了正确的道路。这比我希望的要复杂,但这是我的解决方案。
首先,我必须为 ChildWindow 制作完整的样式,复制所有模板样式(由于后期大小的原因而遗漏了一些):
<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;
}
}
}
我不确定这是最有效的,但它似乎工作得很好。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于您已将应用程序根视觉对象设置为繁忙的微调器,因此您将无法更改 Z 索引,因此它高于 ChildWindow。最好的选择是扩展 ChildWindow 控件并向其中添加一个繁忙的微调器,然后在打开窗口时在 ChildWindow 而不是根视觉对象上设置 IsBusy。
希望有帮助。
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.
您不必子类化 ChildWindow 即可在 ChildWindows 上使用 BusyIndicator。
我正在使用以下解决方案:
1-为所有 ChildWindow 控件定义全局 ContentTemplate。将 IsBusy 属性绑定到 ChildWindow 数据上下文的“IsBusy”。
2- 定义一个单例类,该类在 silverlight 应用程序运行期间准备就绪。我为此选择了 App 类。实现 INotifyPropertyChanged 接口来自动刷新所有 IsBusy 绑定器。实现 IsBusy 属性。实现 ShowBusyIndicator 和 HideBusyIndicator 方法。在 ShowBusyIndicator 方法中迭代所有打开的 ChildWindows 并更新其 DataContext。
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.