将对象绑定到 WPF 的控件中

本文关键字:控件 WPF 对象 绑定 | 更新日期: 2023-09-27 18:31:27

我是 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.Parents() 绑定到 WPF 中的控件。我希望看到这样的东西:


亚当

——彼得,10

- 玛丽,9

凯文

- 贝基,12


它们

都显示在文本框中,我可以更改它们。

提前谢谢。

将对象绑定到 WPF 的控件中

使用带有

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 一起使用(假设 Parent 是 TreeView 的 DataContext 中的一个属性):

<TreeView ItemsSource="{Binding Parents}"/>

如果你不想要树视图,你可以很容易地用ListView列出这个,把你的数据模板改成这样:

    <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}"/>

注意:您可能需要稍微摆弄一下样式,因为开箱即用,这看起来有点废话。您可能至少希望缩进子列表视图(父数据模板中定义的列表视图)并删除其边框。

另请注意:为名称和年龄布局多个文本块的 StackPanel 也不理想,但它既快速又脏。您可能希望以不同的方式处理它。您可以使用(多)转换器来格式化它,使用 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,然后为数据定义一个模板。

如果您不希望使用树视图(这可能是最好的,因为您有一个层次结构 - 尽管它只有一个级别的深度,所以您可能仍然有列表的情况)...
你可以做这样的事情(这是一个粗略的轮廓,你应该填写点)......

<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));  

。并将 AllNode 公开为类似于父级的属性 - 您只需要一个视图模型,并按照建议正确实现 INotifyPropertyChanged

希望这有帮助