如何在WPF中显示窗口列表

时间:2013-09-05 14:33:49

标签: c# wpf data-binding

我正在尝试编写一个程序,其中一部分将显示一个打开的窗口列表(或更具体地说,它们的名称或标题)

因此视图的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本身作为一个控件添加而不是作为一个类(我期望窗口显示文本{{ 1}}或类似的东西)。

我尝试添加System.Windows.Window,但这似乎有相同的结果。

最后,我尝试使用<ItemsControl.ItemTemplate><DataTemplate>...的单个公共属性创建一个虚拟WindowHolder类。这似乎有效,但似乎是一种非常不优雅的做事方式,感觉应该更简单。

TL;博士

问题是“你怎么能简单地(最好是在XAML中)在WPF上显示一个窗口标题列表Window,绑定到视图模型中的ItemsControl

4 个答案:

答案 0 :(得分:2)

您可以使用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的{​​{1}},但由于异常中描述的原因而失败。 ItemsPresenter有效,因为包装容器为ListBox,而不是ListBoxItems。为了在Windows中为Window提供支持,您必须为ItemsControl实现自己的自定义控件,以返回不是ItemsControl的容器。

答案 1 :(得分:1)

我怀疑你已经有了最好的方法 - 听起来像WPF不喜欢填充ItemsControl并引用已经存在于可视树上的元素。

可视化树必须检查引用,因为我已经通过创建一个包装类来测试它,该类包含对Window的引用,然后使用ItemsControl来显示该窗口的内容(到看看我是否可以让它爆炸!)并且它给出了以下错误:

Logical tree depth exceeded while traversing the tree. This could indicate a cycle in the tree.

这是一个无限递归的树

总而言之,最简单的解决方案似乎是为您想要的属性(您已经完成)创建一个包装器,并避免引用叶子节点中的祖先元素!

答案 2 :(得分:0)

您的想法是正确的,您需要为ItemsControl创建一个ItemTemplate。 ItemsControl中的每个项目都是Type Window,您需要在模板中公开Title属性

<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding Title}/>
</DataTemplate>
</ItemsControl.ItemTemplate>

答案 3 :(得分:0)

我要做的是以下内容:

  • 为窗口创建一个接口包装器(如前所述),即带有Title属性的IWindow。
  • 所有Windows都将实现IWindow
  • 制作一个IWindow的Observable集合,而不是Window。