【问题标题】:C# WPF reach an object in ObservableCollection by binding a TreeViewItemC# WPF 通过绑定 TreeViewItem 到达 ObservableCollection 中的对象
【发布时间】:2017-05-16 14:45:41
【问题描述】:

我正在处理一个 WPF 项目,试图从 ImpactElement 对象中获取信息。该对象位于称为 ElementList 的 ObservableCollection 中。这个 ElementList 位于另一个名为 ListOfCreatedStacks 的 ObservableCollection 中,它保存着 Class Stack 的对象。

它只显示来自 ElementList 中的元素 (ImpactElement) 的 toString。我希望从 ElementList 中的每个元素中显示 ImpactElements 变量 ElementMark。

这就是它现在的样子One element added in the ElementList

我可以创建任意数量的堆栈,并且在每个堆栈内都有一个具有不同数量 ImpactElement 的 ElementList。 Two stacks with different amount of ImpactElements in the ElementList

从这些图片中,您可以看到 ElementList 中的每个 ImpactElement 都显示为“IMPACT_Visual_Stacker.Model.ImpactElement”,但我希望它是 ImpactElement 类中的变量 ElementMark。

这是来自不同类的代码。

public class Controller
{
    public ObservableCollection<Stack> ListOfCreatedStacks { get { return listOfCreatedStacks; } set { listOfCreatedStacks = value; } }
}

public class Stack
{
    public ObservableCollection<ImpactElement> ElementList { get { return elementList; } set { elementList = value; } }
    public string Id { get { return id; } set { id = value; } }
}

public class ImpactElement
{
    private string elementMark;
    private int id;
    private Vector3 sizeLWH;
    private Vector3 positionXYZ;
    private Vector3 rotationXYZ;
    private Mesh elementMesh;
}

这是 XAML 部分。

 <ListView ItemsSource="{Binding ListOfCreatedStacks}" HorizontalAlignment="Left" Margin="350, 200,0,0" Width="300">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TreeViewItem
                    Header="{Binding Id}"
                    IsExpanded="True">
                    <TreeViewItem
                        ItemsSource="{Binding ElementList}"  Header="{Binding ElementMark}" IsExpanded="True">
                    </TreeViewItem>
                </TreeViewItem>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

我尝试了从 Ed 那里得到的另一个 StackOverflow 的解决方案。 结果最终只添加了一个包含我的“ImpactElement”对象的 Hiarchy 对象。

这是经过测试的 XAML 的样子:

 <ListView ItemsSource="{Binding ListOfCreatedStacks}" HorizontalAlignment="Left" Margin="350, 200,0,0" Width="300">
        <ListView.ItemTemplate>
            <HierarchicalDataTemplate DataType="{x:Type System:String}"
                                      ItemsSource="{Binding ListOfCreatedStacks}">
                <TreeViewItem
                    Header="{Binding Id}"
                    IsExpanded="True">
                    <HierarchicalDataTemplate DataType="{x:Type System:String}"
                                              ItemsSource="{Binding ElementList}">
                        <TreeViewItem
                            Header="{Binding ElementMark}"
                            IsExpanded="True">
                        </TreeViewItem>
                    </HierarchicalDataTemplate>
                </TreeViewItem>
            </HierarchicalDataTemplate>

        </ListView.ItemTemplate>

    </ListView>

感觉像是错过了一些我不明白的简单部分。感谢您的帮助。

【问题讨论】:

  • 感谢 Ed 的回复。在那个问题上这是一个很好的答案。由于我没有相同的孩子和父母而不是 Hierachy,我不知道如何应用它?
  • 使用 HierarchicalDataTemplate。如果您无法根据自己的需要修改该答案,请就您遇到麻烦的地方提出另一个问题。如果您不愿意尝试,我很抱歉,但我帮不了您。
  • 嗨,埃德。我已经从您发送的答案中尝试了解决方案。我无法让它工作。我更新了原始问题。你看到我想念什么了吗?
  • 你为什么要将TreeViewItem嵌套在ListView而不是TreeView中?

标签: c# wpf treeviewitem


【解决方案1】:

首先,ControllerElementListImpactElement 可能应该实现 INotifyPropertyChanged。你可以在 Stack Overflow 和其他地方找到一百万个这样的例子。这很简单,如果您遇到任何障碍,您可以在这里获得帮助。

如果您在这些对象在 UI 中可见时更改了这些对象上的任何绑定属性值,则会导致 UI 更新。如果您添加或删除项目,ObservableCollections 将通知 UI,但如果其中一个项目的某些属性发生更改,它们将无法通知 UI。

其次,ImpactElement 只有私有字段。由于在其他类上省略了私有字段,我猜这只是您复制代码时的疏忽。但是您只能绑定到公共属性。必须是公开的,必须是带有 get 并且通常是 set 的属性。

我希望您已将Controller 的实例分配给您的DataContext。如果你不这样做,树将不会填充。

起初我发现 WPF 的 TreeView 令人费解,当我第一次看到它时,我对 XAML 并不陌生。做一堆简单的例子(如果需要可以来这里寻求帮助),不要只是粘贴我给你的 XAML。它会迅速聚焦。

最后,您在 XAML 中做了很多示例中没有做的事情。我不知道你为什么做那些事,但你不能随便做事。效果不好。但正如我所说,这个学习曲线很艰难,所以没有伤害。

这是 XAML:

<TreeView 
    ItemsSource="{Binding ListOfCreatedStacks}" 
    HorizontalAlignment="Left" 
    Margin="350, 200,0,0"
    Width="300">
    <TreeView.ItemContainerStyle>
        <Style 
            TargetType="TreeViewItem" 
            BasedOn="{StaticResource {x:Type TreeViewItem}}"
            >
            <Setter Property="IsExpanded" Value="True" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate 
            DataType="{x:Type local:Stack}"
            ItemsSource="{Binding ElementList}"
            >
            <Label Content="{Binding Id}" />
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate 
                    DataType="{x:Type local:ImpactElement}"
                    >
                    <Label Content="{Binding ElementMark}" />
                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

所以 TreeView 的 ItemsSource 是 ListOfCreatedStacks

我们给TreeView 一个ItemContainerStyle,它将应用于树中的每个TreeViewItem。我们这样做只是为了设置IsExpanded。没有其他方法可以访问TreeViewItems。我们可以也给顶级项目模板一个它自己的ItemContainerStyle,如果我们想对它们做一些不同的事情,它只会影响它的孩子。但我们不需要。

我们给TreeView 一个ItemTemplate。这就是我们如何显示TreeViewItem 如何显示TreeView 的其中一个孩子。当您查看HierarchicalDataTemplate 时,它有点像TreeView:它有一个ItemsSource,我们将其绑定到Stack 的一个属性,其中包含@987654350 的孩子 @。它有一个ItemTemplate 给它自己的孩子。它可以,正如我所说,有一个ItemContainerStyle,但我们让它继承我们在TreeView 上设置的那个。

它是递归的:一个树节点很像一棵整棵树。

如果您不给HierarchicalDataTemplateItemTemplate 提供它自己的TreeViewItems,那么它所适用的TreeViewItems 只会将其用作自己孩子的模板,孩子也会这样做。如果您为ImpactElement 提供ImpactElements 的子集合,则树可能有两打层深,而无需在上面的XAML 中进行任何更改。

任何DataTemplateHierarchicalDataTempate 都可以具有DataType 属性。这是模板显示的视图模型项的类型。我不知道你从哪里得到System:String

在这种特殊情况下1DataType 没有任何作用,只是帮助您在编辑 XAML 时保持直截了当:它提醒您哪个模板在哪个递归级别适用于哪个收集项目,他的智能感知也可以帮助你。

终于有了HierarchicalDataTempate的内容:

<Label Content="{Binding Id}" />

这可以是任何单个 XAML 元素,但如果需要,它可以是包含整个 UI 的 GridStackPanel。你可以在里面放任何东西。你可以在里面放一个完全不同的TreeView

最后,您应该学会使用StackPanelGrid 列和行进行布局。如果您想重新安排任何事情,这种保证金业务就是一场噩梦。我想你在 VS 中使用设计模式?我只使用它来预览我在 XAML 中手动完成的工作。正确完成后,在 XAML 布局中,所有内容都相对于其父级和兄弟级进行定位。也许它有一个固定的宽度和/或高度,通常是一个小的边距——个位数——只是为了在邻居之间创造空间,而不是为了绝对定位。一旦你习惯了它,这是一种非常好的处理东西的方式。很像 HTML。


1 对于DataTemplateHierarchicalDataTemplateDataType 属性的其他用途,请参阅"implicit datatemplates",这里是more complicated example for doing it with treeview items。如果你已经在努力消化这一切,不要去看那些东西,只关注我上面给你的案例。这绰绰有余。数据模板是一条学习曲线,添加递归只会让一切变得更奇怪。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-03
    • 1970-01-01
    • 2017-04-16
    • 2019-10-31
    • 2013-10-14
    相关资源
    最近更新 更多