如何使用 DataTemplate 在 ListBox 中自定义显示?

How to have a custom display in ListBox with DataTemplate?

我需要以特定布局在 ListBox 中显示卡片:

https://imgur.com/a/0U8eqTc

我试图找到一种使用两种类型的 DataTemplate 的方法,但我不知道该怎么做。我决定制作一个包含 6 张卡片的模板(如下所示):

https://imgur.com/VrOlYcR

这是我当前模板的样子:

<ControlTemplate x:Key = "CardTemplate" TargetType = "Button">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Image Grid.Row="0" Source="{Binding Path=Image}"/>
        <TextBlock Grid.Row="1" Text="{Binding Path=Titre}"/>
    </Grid>
</ControlTemplate>

<DataTemplate x:Key="DataTemplate">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>

        <Button Grid.Column="0" Grid.Row="0" Template="{StaticResource CardTemplate}"/>

        <Grid Grid.Column="1" Grid.Row="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0" Template="{StaticResource CardTemplate}"/>
            <Button Grid.Row="1" Template="{StaticResource CardTemplate}"/>
        </Grid>

        <Grid Grid.Column="0" Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0" Template="{StaticResource CardTemplate}"/>
            <Button Grid.Row="1" Template="{StaticResource CardTemplate}"/>
        </Grid>

        <Button Grid.Column="1" Grid.Row="1" Template="{StaticResource CardTemplate}"/>

    </Grid>
</DataTemplate>

我打算在列表框中显示:

<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
         Name="ListBox" ItemTemplate="{DynamicResource DataTemplate}" 
         ScrollBar.Scroll="ScrollOnBottom">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

下面是我的鳕鱼的基本工作原理:

class Cards
{
    public List<Card> cards; // list of 6 Card objects
}

class Card
{
    string title;
    BitmapImage image;

    public string Title { get => title; set => title = value; }
    public BitmapImage Image { get => image; set => image = value; }
}

ObservableCollection<Cards> cc = new ObservableCollection<Cards>();
/*

Cards are already filled with 6 Card
cc filled with Cards

*/
formationListBox.ItemsSource = cc;

问题出在这里,它显示了正确数量的卡片,但按钮是空的。我不知道如何将特定对象绑定到每个按钮。

举个 Sinatr 评论的例子。您应该从 Mvvm 的角度来处理这个问题。首先,您应该为这个 Window 所在的视图添加一个视图模型。这将包含一个对象列表 DisplayCards 每个对象将存储字符串和图像。

public class DisplayCard : INotifyPropertyChanged
{
    private string _title;
    public string Title
    {
        get { return _title; }
        set
        {
            if (value != _title) { _title = value; RaisePropertyChanged(); }
        }
    }
    private string _cardImage;
    public string CardImage
    {
        get { return _cardImage; }
        set
        {
            if (value != _cardImage) { _cardImage = value; RaisePropertyChanged(); }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class YourViewVM : INotifyPropertyChanged
{
    private ObservableCollection<DisplayCard> _cardCollection;
    public ObservableCollection<DisplayCard> CardCollection
    {
        get { return _cardCollection; }
        set
        {
            if (value != _cardCollection) { _cardCollection = value; RaisePropertyChanged(); }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

然后您需要将列表 CardCollection 设置为 ListBox 的 ItemSource。然后使用数据模板将 DisplayCards 属性绑定到包含对象。

<ListBox Name="lbTodoList" HorizontalContentAlignment="Stretch" ItemSource="{Binding CardCollection}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="4*"/>
          <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Image Grid.Row="0" Source="{Binding Image}"/>
        <TextBlock Grid.Row="1" Text="{Binding Title}"/>
      </Grid>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

您需要确保将 YourViewVM 设置为视图的 DataContext。一个简单的搜索应该解决如何做到这一点。

以上内容应该足以让您重构代码以使其正常工作。