0

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

因此视图的 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>...,但这似乎有相同的结果。

最后,我尝试WindowHolder使用 a 的单个公共属性创建一个虚拟类Window。这似乎可行,但似乎是一种非常不优雅的做事方式,感觉应该更简单。

tl;博士

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

4

4 回答 4

2

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

于 2013-09-05T15:10:20.157 回答
1

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

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

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

这是一棵无限递归的树

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

于 2013-09-05T15:43:06.520 回答
0

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

<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding Title}/>
</DataTemplate>
</ItemsControl.ItemTemplate>
于 2013-09-05T14:42:37.617 回答
0

那么我会做的是以下几点:

  • 为窗口创建一个接口包装器(如前所述),即具有 Title 属性的 IWindow。
  • 所有 Windows 都将实现 IWindow
  • 制作 IWindow 的 Observable 集合,而不是 Window。
于 2013-09-05T15:01:50.137 回答