C#WPF通过绑定TreeViewItem到达ObservableCollection中的对象

时间:2017-05-16 14:45:41

标签: c# wpf treeviewitem

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

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

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

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

从这些图片中可以看到ElementList中的每个ImpactElement都显示为“IMPACT_Visual_Stacker.Model.ImpactElement”,但我希望它是ImpactElement Class中的变量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”对象的Hiearchy对象。

这是经过测试的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>

感觉就像想念一些我不理解的简单部分。谢谢你的帮助。

1 个答案:

答案 0 :(得分:0)

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

如果您在UI中看到这些对象时更改了这些对象的任何绑定属性值,那么它将会导致UI更新。如果您添加或删除项目,ObservableCollection将通知用户界面,但如果其中一个项目的某些属性发生变化,则无法通知用户界面。

其次,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。没有其他方法可以到达TreeViewItem。我们可以也为顶级项目模板提供自己的ItemContainerStyle,如果我们想要做一些与之不同的事情,这只会影响其子项。但我们不需要。

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

它是递归的:树节点非常像整棵树。

如果你没有给自己TreeView HierarchicalDataTemplate,那么它适用的ItemTemplate只会使用那个作为自己孩子和孩子的模板也会这样做。如果你给TreeViewItems ImpactElementImpactElement个子集合,那么这个树可能有二十几个级别而不会在上面的XAML中进行一次更改。

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

在这个特殊情况下 1 DataType没有任何意义,只是为了帮助你在编辑XAML时保持正确:它会提醒你哪个模板的递归级别适用收集项目,他的Intellisense也帮助你。

最后,我们有HierarchicalDataTempate的内容:

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

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

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

1 对于DataTypeDataTemplate的{​​{1}}属性的其他用途,请参阅"implicit datatemplates",此处为{{3} }}。如果你已经在努力消化所有这些,不要去看那些东西,只关注我上面给你的情况。这绰绰有余。数据模板是一种学习曲线,添加递归只会让所有东西更加怪异。