如何在WPF中显示窗口列表
本文关键字:显示 窗口 列表 WPF | 更新日期: 2023-09-27 18:30:14
我正在尝试编写一个程序,其中一部分将显示打开窗口的列表(或者更具体地说,它们的名称或标题)
因此,视图的XAML如下所示:
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<ItemsControl ItemsSource="{Binding Windows}" />
并且ViewModel
类看起来像这样:
public ObservableCollection<Window> Windows { get; set; }
public ViewModel()
{
this.Windows = new ObservableCollection<Window>();
this.Windows.Add(new Window());
}
这导致程序(和设计器视图)抛出InvalidOperationException: Window must be the root of the tree. Cannot add Window as a child of Visual.
问题似乎是ItemsControl
认为我实际上想将Window
本身添加为控件,而不是类(我希望窗口显示文本System.Windows.Window
或类似内容)。
我试过添加<ItemsControl.ItemTemplate><DataTemplate>...
,但结果似乎是一样的。
最后,我尝试创建一个具有单个公共属性Window
的伪WindowHolder
类。这似乎有效,但似乎是一种非常不雅的做事方式,感觉应该更简单。
tl;dr
问题是"如何在视图模型中绑定到ObservableCollection<Window>
的WPF ItemsControl
上简单地(最好是在XAML中)显示窗口标题列表?
您可以使用ListBox
而不是ItemsControl
<ListBox ItemsSource="{Binding Windows}">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
问题是,将控件添加到通用ItemsControl
的默认行为导致ContentPresenter
被封装在控件本身中。因此,您的集合Windows
将希望作为容器添加到ItemsControl
的ItemsPresenter
中,但由于异常中描述的原因,它失败了。ListBox
之所以有效,是因为包装容器是ListBoxItems
,而不是Windows
。为了在ItemsControl
中为Window
提供支持,您必须为ItemsControl
实现自己的自定义控件,以返回非Window
的容器。
我怀疑你已经找到了最好的方法——听起来WPF不喜欢用对视觉树上已经存在的元素的引用来填充ItemsControl
。
可视化树必须检查引用,因为我已经通过创建一个包装类来测试了这一点,该包装类具有对Window
的引用,然后使用ItemsControl
来显示该窗口的内容(看看我是否可以使其爆炸!),它给出了以下错误:
Logical tree depth exceeded while traversing the tree. This could indicate a cycle in the tree.
这是一个无限递归树
总之,最简单的解决方案似乎是为您想要的属性创建一个包装器(您已经完成了),并避免在叶/子节点中引用祖先元素!
您的想法是正确的,您需要为ItemsControl创建一个ItemTemplate。ItemsControl中的每个项都将是Window类型,并且您需要在模板中公开Title属性
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding Title}/>
</DataTemplate>
</ItemsControl.ItemTemplate>
我要做的是:
- 为具有Title属性的窗口ie IWindow创建一个接口包装器(如前所述)
- 所有Windows都将实现IWindow
- 制作IWindow的Observable集合,而不是Window