我是WPF的新手,我想快速建议如何将此对象绑定到wpf控件,我不知道应该使用哪个控件:
public class Parent
{
public string Name{get; set;}
public List<Child> Childs {get; set;}
}
public class Child
{
public string Name{get; set;}
public int Age {get; set;}
}
public class ParentFactory
{
public List<Parent> Parents {get; set;}
public ParentFactory()
{
Child child1 = new Child() {Name="Peter", Age=10;};
Child child2 = new Child() {Name="Mary", Age=9;};
Child child3 = new Child() {Name="Becky", Age=12;};
Parent parent1 = new Parent(){Name="Adam", Childs = new List<Child<>(){child1, child2}};
Parent parent2 = new Parent(){Name="Kevin", Childs = new List<Child<>(){child3}};
Parents = new List<Parent>(){parent1, parent2};
}
}
创建此实例后:
ParentFactory parentFactory = new ParentFactory();
我想将parentFactory.Parents()绑定到WPF中的控件。我希望看到这样的事情:
亚当
- 彼得,10岁
- 玛丽,9岁
凯文
- Becky,12岁
它们都显示在文本框中,我可以更改它们。
提前致谢。
答案 0 :(得分:4)
将TreeView与HierarchicalDataTemplate一起使用。
但请注意,如果没有在模型上实现INotifyPropertyChanged,则绑定不会在任何属性更改时更新。此外,如果不使用ObservableCollections替换列表,则在向列表中添加更多项目时,视图将不会更新。
这样的事情应该有效,首先要定义你的模板:
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Parent}" ItemsSource="{Binding Childs}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Child}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock>, </TextBlock>
<TextBlock Text="{Binding Age}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
然后你可以像这样使用TreeView(假设Parents是TreeView的DataContext中的属性):
<TreeView ItemsSource="{Binding Parents}"/>
如果您不想使用TreeView,可以使用ListView轻松执行此操作,将DataTemplates更改为:
<DataTemplate DataType="{x:Type local:Parent}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<ListView ItemsSource="{Binding Childs}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Child}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock>, </TextBlock>
<TextBlock Text="{Binding Age}"/>
</StackPanel>
</DataTemplate>
然后你可以像这样绑定它:
<ListView ItemsSource="{Binding Parents}"/>
注意:你可能想稍微调整一下风格,因为开箱即用,这看起来有点废话。您可能希望至少缩进子ListView(在Parent DataTemplate中定义的那个)并摆脱它的边界。
另请注意:StackPanel为名称和年龄布局多个TextBlock也不理想,但它快速而又脏。您可能希望以不同方式处理它。您可以使用(多)转换器对其进行格式化,使用StringFormat或将另一个属性添加到模型中以供显示,甚至只是覆盖子类的ToString。
另一个编辑
使用DataGrid的快速(丑陋)示例:
<DataGrid ItemsSource="{Binding Parents}" AutoGenerateColumns="False">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding Childs}"/>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}"/>
</DataGrid.Columns>
</DataGrid>
这会使用行详细信息模板将数据网格放入数据网格中。如果单击一行,它会将子项显示为行详细信息。如果希望详细信息始终可用,则可以删除RowDetailsTemplate并将DataGridTextColumn替换为DataGridTemplateColumn,然后为您的数据定义模板。
答案 1 :(得分:3)
如果您不希望树视图(这可能是最好的,因为您有一个层次结构 - 虽然它只是一个级别的深度,所以您可能仍然有一个列表的情况)...
你可以做这样的事情(这是一个粗略的轮廓,你应该填写点)......
<ItemsControl ItemsSource="{Binding AllNodes}">
</ItemsControl>
...并且具体为每种类型定义模板,如Matt所提到的......
<DataTemplate DataType="{x:Type namespace:Child}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type namespace:Parent}">
...
</DataTemplate>
...虽然AllNodes
是您需要flatten
所需的列表,但您可以使用此...
var allnodes = Parents.SelectMany(p => new object[]{p}.Concat(p.Childs));
...并将AllNodes公开为类似于Parent的属性 - 您只需要一个View Model,并按照建议正确实现INotifyPropertyChanged。
希望这会有所帮助