【问题标题】:how can i display hierarchical data in a list box using data templates in wpf如何使用 wpf 中的数据模板在列表框中显示分层数据
【发布时间】:2012-02-20 19:13:54
【问题描述】:

我有一个组和子组的分层集合,例如:

  • 第 1 组
    • 子组 1
    • 子组2
  • 第 2 组
    • 子组 1

我想要做的是在列表框中显示此分层数据。我尝试创建不同的数据模板,并且能够显示子组但无法显示组名。

我为此目的使用的类是这样的:

public class Groups
{
public string Group {get; set;}
public List<string> SubGroup {get; set;}
}

我将一个列表绑定到列表框的 ItemsSource。我需要的是一个数据模板,我可以用它来分层显示这些数据。

我不能为此使用其他控件,我必须使用列表框。

编辑: 通过查看 Desty 提供的建议,我可以使用此数据模板显示值

<DataTemplate x:Key="SubGroups">
  <StackPanel>
    <Label Content="{Binding Path=Group}" />
    <ItemsControl Margin="30,0,0,0" ItemsSource="{Binding SubGroup}" />
  </StackPanel>
</DataTemplate>

现在的问题是我无法从列表框中选择单个子组。它选择了完整的 ListBoxItem,我无法选择单个子组。

【问题讨论】:

  • 为什么必须使用 ListBox 而不是 TreeView,其目的是显示分层数据?
  • 您是否尝试过指定递归数据模板?我不确定这是否可行,但值得一试。
  • @djacobson: 使用列表框是客户的要求:( @mydogisbox: 我如何创建递归数据模板?你能发布一些代码吗?
  • 您是否注意到,帖子很少的人似乎有较高比例的客户指定必须使用什么工具。

标签: c# .net wpf listbox


【解决方案1】:

您需要为 SubGroups 定义第二个类,因此您可以为 Groups 定义一个 DataTemplate,为 SubGroups 定义一个。您的模型类可能类似于

public class Group {
  public string Name { get; set; }
  public List<SubGroup> SubGroups { get; set; }
  public Group(string name) { this.Name = name; }
}

public class SubGroup {
  public string Name { get; set; }
  public SubGroup(string name) { this.Name = name; }
}

在 WPF 中,您可以为每种类型定义一个 DataTemplate:

<Window.Resources>
  <DataTemplate DataType="{x:Type local:SubGroup}">
    <StackPanel Orientation="Horizontal">
      <TextBlock Text=" +-- "/><TextBlock Text="{Binding Name}"/>
    </StackPanel>
  </DataTemplate>
  <DataTemplate DataType="{x:Type local:Group}">
    <StackPanel>
      <TextBlock Text="{Binding Name}"/>
      <ItemsControl ItemsSource="{Binding SubGroups}"/>
     </StackPanel>
  </DataTemplate>
</Window.Resources>
<Grid>
  <ListBox ItemsSource="{Binding}" />
</Grid>

编辑(在查看 Bhattis 编辑后):

如果子组项目也应该是可点击的,那么(恕我直言)从 ListBox 的角度来看,组和子组之间没有区别。所以我的解决方法猜测是:

public class Groups {
  public string Group { get; set; }
} 

在 WPF 窗口中

<ListBox ItemsSource="{Binding}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel>
        <Label Content="{Binding Path=Group}" />
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

并且在 WPF 代码隐藏文件中:

public MainWindow() {
  InitializeComponent();
  Groups g1 = new Groups() { Group = "Parent 1" };
  Groups s1 = new Groups() { Group = "   Sub 1" };
  Groups s2 = new Groups() { Group = "   Sub 2" };
  Groups g2 = new Groups() { Group = "Parent 2" };
  Groups s3 = new Groups() { Group = "   Sub 1" };
  Groups s4 = new Groups() { Group = "   Sub 2" };
  this.DataContext = new List<Groups>() { g1, s1, s2, g2, s3, s4 };
}

这里的每个子组都只是一个组,因此每条“行”都是可点击的。重要的是列表的顺序很重要,因为结构不再在模型中。

如果您必须根据用户单击组还是子组做出不同的反应,那么您可以在模型中构建继承层次结构并将相应的对象放入 DataContext 中。为了把你引向正确的方向,我的意思是像

public abstract class AbstractGroup {
    public string Name { get; set; }
    public AbstractGroup(string name) { this.Name = name; }
}
public class Group : AbstractGroup {
    public Group(string name) : base(name) {}
}
public class SubGroup : AbstractGroup {
    public SubGroup(string name) : base(name) {}
} 

代码隐藏:

    InitializeComponent();
    AbstractGroup g1 = new Group("Parent 1");
    AbstractGroup s1 = new SubGroup("  Sub 1");
    AbstractGroup s2 = new SubGroup("   Sub 2");
    AbstractGroup g2 = new Group("Parent 2");
    AbstractGroup s3 = new SubGroup("   Sub 1");
    AbstractGroup s4 = new SubGroup("   Sub 2");
    this.DataContext = new List<AbstractGroup>() { g1, s1, s2, g2, s3, s4 };

XAML:

<ListBox ItemsSource="{Binding}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel>
        <Label Content="{Binding Path=Name}" />
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

由于您可以在 DataContext 中获取所选对象,因此 typeof() 可以帮助您找出所选项目的具体类型。

【讨论】:

  • 我在查看您的答案后编辑了问题。我现在无法选择单个子组。我该怎么做?
  • @Bhatti 我担心在这种情况下你必须使用一个糟糕的解决方法,如果你不允许使用像 TreeView 这样的其他控件。我已经编辑了我的答案。
  • 是的,解决方法对我有用..希望有更好的方法来做到这一点......但非常感谢您的帮助和时间
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
相关资源
最近更新 更多