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

Posted

技术标签:

【中文标题】如何使用 DataTemplate 在 ListBox 中进行自定义显示?【英文标题】:How to have a custom display in ListBox with DataTemplate? 【发布时间】:2019-10-10 21:42:14 【问题描述】:

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

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

我试图找到一种方法来使用 2 种类型的 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 中显示的内容:

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

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

【问题讨论】:

您必须使用属性,而不是字段。该按钮可以在您的视图模型中将其Command 绑定到ICommand。了解 MVVM。 【参考方案1】:

举一个 Sinatr 评论的例子。你应该从 Mvvm 的角度来处理这个问题。首先你应该为这个窗口所在的视图添加一个视图模型。这将包含一个对象列表,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。一个简单的搜索应该解决如何做到这一点。

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

【讨论】:

以上是关于如何使用 DataTemplate 在 ListBox 中进行自定义显示?的主要内容,如果未能解决你的问题,请参考以下文章

[UWP]如何使用代码创建DataTemplate(或者ControlTemplate)

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

如何设置控件属性(在DataTemplate和UserControl中)的绑定以使用ItemSource的给定属性?

如何使用类似表格的 DataTemplate 在 UWP ListView 中动态缩放列宽

如何将 DataTemplate 数据类型绑定到接口?

如何使用 DataTemplate 访问列表框中的特定项目?