如何将一个列表的列表绑定到 ListView 控件

3

我有以下结构

QPage类对象包含一个List<List<QLine>> QLine对象包含List<Qword>

每个单词列表构成一行,每个行的列表构成一个组(段落),每个段落的列表构成一页。

我想将页面绑定到XAML中的这种结构。

<ListView>
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <TextBlock>                 
            </TextBlock>
        </StackPanel>
    </StackPanel>
</ListView>

每个ListView项都是一个段落(List<QLine>),每个垂直堆栈面板都包含一个List<QLine>的项,每个水平堆栈面板都包含一个List<Qword>的项,而textblock则绑定到Qword.text属性。我不知道如何在XAML代码中进行此类绑定。


这很有趣,给它点个赞。但是首先,您应该为ListView提供某种ID,以便在代码后台中可以执行listView.Source = ....;。然后,在XAML中的TextBlock中,您可以执行Text = {Binding TheObjectName},其中TheObjectName可以是QWord。最后,我不会让结构不明确,即List<List<QLine>>。我会使其全部位于对象结构内,即包含那些对象的类,这将有助于绑定,当提供XAML中属性的名称时。 - Subby
4个回答

4
希望我没有漏掉任何列表,但这应该可以工作。基本上,它是一个名为QPageListListBox,其中包含List<List<QLine>>。然后您有一个ItemsControl,它在垂直面板中托管每个List<QLine>,最后还有另一个ItemsControl,它从QLine中托管List<Qword>(称其为QwordList),其中每个QWord都显示为水平StackPanel上的TextBlock
<!-- ItemsSource: List<List<QLine>>, Item: List<QLine> -->
<ListBox ItemsSource="{Binding QPageList}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <!-- ItemsSource: List<QLine>, Item: QLine -->
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <!-- ItemsSource: QLine.List<QWord>, Item: QWord --> 
                        <ItemsControl ItemsSource="{Binding QwordList}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Horizontal"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <!-- Item: QWord -->
                                    <TextBlock Text="{Binding text}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

就是这样了。你只是忘记绑定到QLine :) - Alex
1
我这样做了吗?在所有这些列表中可能性很大,但我刚刚添加了带有类型的注释,我认为它应该可以工作。 - dkozl
我认为你实际上没有这样做,因为你无法绑定到line,没有line对象,只有list<list<line>>和list<word>。你的解决方案按原样工作。非常感谢 :) - smohamed
我改正了:)。今天也不是第一次了。可能是周一的原因,我也不知道。 - Alex

1
你需要的是 ListView.ItemTemplate。基本上,你需要为列表提供一种理解行嵌套数据结构的方式。
这里有一个很好的教程可以帮助你开始使用ItemTemplates
一旦你的列表有了项模板,那么你只需要直接将 ListView 绑定到你的数据源,就完成了。

0

希望这会对你有所帮助。来自这里

Authors (list)
 - - Name
 - - Books (list)
     | -  - Title
     | -  - Contents

示例代码:

  <Window.Resources>
    <DataTemplate x:Key="ItemTemplate1">
      <StackPanel>
        <TextBlock Text="{Binding Name}"/>
      </StackPanel>
    </DataTemplate>
    <DataTemplate x:Key="ItemTemplate2">
      <StackPanel>
        <TextBlock Text="{Binding Title}"/>
      </StackPanel>
    </DataTemplate>
  </Window.Resources>
  <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource AuthorDataSource}}">
    <ListBox x:Name="AuthorList" ItemTemplate="{DynamicResource ItemTemplate1}" ItemsSource="{Binding Authors }" >
    <ListBox x:Name="BookList"  DataContext="{Binding SelectedItem, ElementName=AuthorList}" ItemsSource="{Binding Books }" ItemTemplate="{DynamicResource ItemTemplate2}" />
    <TextBlock  x:Name="BookContent"   DataContext="{Binding SelectedItem, ElementName=BookList}"  Text="{Binding Contents }" />
  </Grid>

使用网格来做这件事感觉有些奇怪。此外,您会失去列表的虚拟化功能。在足够大的列表上,这将损害您应用程序的性能。我想任何具有1000个项目的东西都会使其无法使用。 - Alex
@Alex 但是网格是一个布局面板,它以行和列的表格结构排列其子控件,我不明白这怎么会增加大量的性能开销。 - Paul Zahra
它将尝试渲染所有子控件。ListView和其他一些控件使用虚拟化来重用可见组件以在滚动时呈现绑定数据。基本上,您正在滚动数据而不是可见元素。 - Alex
虚拟化不是由视口的大小所决定吗?即为子控件“ItemsControl”或ListBox设置大小,您就可以在网格中实现虚拟化。此外,我不想对列表的大小和最佳方案做任何假设,即将大型列表保存在内存中可能不是最好的选择。 - Paul Zahra
不是这样的。否则就没有必要使用VirtualizingStackPanel了 :) - Alex
显示剩余3条评论

0

继续Alex所说的,将对象封装在类中是个好主意,即:

Encapsulate(如果这里用的是正确的词)。

public class Page
{
    public List<Paragraph> Paragraphs { get; set; }
}

public class Paragraph
{
    public List<QWord> Sentences { get; set; }
}

public class Sentence
{
    public List<QWord> Words { get; set; }
}

这将有助于在XAML中绑定数据,即如果您查看Alex提供的教程:

<TextBlock Text="Name: " />
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<TextBlock Text="{Binding Age}" FontWeight="Bold" />
<TextBlock Text=" (" />
<TextBlock Text="{Binding Mail}" TextDecorations="Underline" Foreground="Blue" Cursor="Hand" />
<TextBlock Text=")" />

希望这能对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接