在 ListBox 中使用 DataTemplate

假设我们有以下 XAML 片段:

<ListBox x:Name="MyListBox" />

然后在这个 XAML 文件的代码隐藏中,我们在构造函数中编写以下内容:

MyListBox.ItemsSource = new[]
{
    1, 2, 3, 4, 5
};

运行应用程序,我们得到一个我们输入的数字列表。

StackOverflow 文档

但是,如果我们尝试显示自定义类型的对象列表,就像这样

MyListBox.ItemsSource = new[]
{
    new Book { Title = "The Hitchhiker's Guide to the Galaxy", Author = "Douglas Adams" },
    new Book { Title = "The Restaurant at the End of the Universe", Author = "Douglas Adams" },
    new Book { Title = "Life, the Universe and Everything", Author = "Douglas Adams" },
    new Book { Title = "So Long, and Thanks for All the Fish", Author = "Douglas Adams" },
    new Book { Title = "Mostly Harmless", Author = "Douglas Adams" }
};

假设我们有一个名为 Book 的类

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
}

然后列表看起来像这样:

StackOverflow 文档

虽然我们可以假设 ListBox 将足够智能来恰当地显示我们的书籍对象,但我们实际看到的是 Book 类型的全名。ListBox 实际上在这里做的是在它想要显示的对象上调用内置的 ToString() 方法,虽然在数字的情况下产生了理想的结果,但在自定义类的对象上调用 ToString() 会导致获得其类型的名称,如在截图上看到。

我们可以通过为我们的书类编写 ToString() 来解决这个问题,即

public override string ToString()
{
    return Title;
}

StackOverflow 文档

但是,这不是很灵活。如果我们想要展示作者怎么办?我们也可以将它写入 ToString,但如果我们不想在应用程序的所有列表中呢?如何展示漂亮的书籍封面?

这就是 DataTemplates 可以提供帮助的地方。它们是 XAML 的片段,可以根据需要实例化,根据创建的源数据填充详细信息。简单地说,如果我们扩展 ListBox 代码如下:

<ListBox x:Name="MyListBox">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Title}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

然后列表将为其源中的每个项创建一个 TextBox,这些 TextBox 将使用来自我们对象的 Title 属性的值填充Text 属性。

如果我们现在运行应用程序,我们将得到与上面相同的输出,*即使我们删除自定义 ToString 实现。对此有利的是,我们可以自定义此模板,远远超出简单的 string(和 ToString)的功能。我们可以使用我们想要的任何 XAML 元素,包括自定义元素,并且可以将它们的值绑定到来自对象的实际数据(如上例中的 Title)。例如,按如下方式扩展模板:

<ListBox x:Name="MyListBox">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock FontStyle="Italic" Text="{Binding Author}" />
                <TextBlock FontSize="18" Text="{Binding Title}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

然后我们得到了一个很好的格式化的书籍视图!

StackOverflow 文档