#448 – 在Grid中显示数据绑定元素的集合(Data Binding Elements in a Collection to a Grid)

假设你有一个集合,想将集合的数据显示在Grid上,数据所显示行和列根据集合的内容动态设置。你需要在集合的单个实例中有指定行和列的属性并对其进行绑定。

你可以使用Grid 面板作为ItemsControlItemsPanel 。这样子元素将以Grid 的方式进行布局。然后你可以设置ItemTemplate 属性确定如何显示每个子项的内容。

首先你可以试着用下面的代码:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow">
    <ItemsControl ItemsSource="{Binding ChessPieces}" Height="500" Width="500">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid ShowGridLines="True">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Label Content="{Binding Text}" Grid.Row="{Binding Row}" Grid.Column="{Binding Column}"
                    HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

上面的代码中ItemsPanel 为一个8行8列的Grid ,用以显示集合。并且将集合ChessPieces绑定到ItemsSource 。下面是ChessPieces的定义,并添加两行实例进行测试:

public ObservableCollection<ChessPiece> ChessPieces { get; private set; }
ChessPieces = new ObservableCollection<ChessPiece>();
ChessPieces.Add(new ChessPiece("QR-Blk", 1, 0));
ChessPieces.Add(new ChessPiece("QN-Blk", 1, 1));
ChessPieces.Add(new ChessPiece("QB-Blk", 1, 2));
ChessPieces.Add(new ChessPiece("Q-Blk", 1, 3));
ChessPieces.Add(new ChessPiece("K-Blk", 1, 4));
ChessPieces.Add(new ChessPiece("KB-Blk", 1, 5));
ChessPieces.Add(new ChessPiece("KN-Blk", 1, 6));
ChessPieces.Add(new ChessPiece("KR-Blk", 1, 7));
 
ChessPieces.Add(new ChessPiece("P1-Blk", 2, 0));
ChessPieces.Add(new ChessPiece("P2-Blk", 2, 1));
ChessPieces.Add(new ChessPiece("P3-Blk", 2, 2));
ChessPieces.Add(new ChessPiece("P4-Blk", 2, 3));
ChessPieces.Add(new ChessPiece("P5-Blk", 2, 4));
ChessPieces.Add(new ChessPiece("P6-Blk", 2, 5));
ChessPieces.Add(new ChessPiece("P7-Blk", 2, 6));
ChessPieces.Add(new ChessPiece("P8-Blk", 2, 7));
//OnPropertyChanged("ChessPieces");

ChessPiece的定义:

        public class ChessPiece
        {
            public ChessPiece(string text, int row, int column)
            {
                this.Text = text;
                this.Row = row;
                this.Column = column;
            }

            public string Text { get; set; }

            public int Row { get; set; }

            public int Column { get; set; }
        }

到现在为止,每个元素都已经显示在了Grid面板中,但是并没有显示在预想的位置,而是全部显示在0行0列。Grid.RowGrid.Column 附加属性被忽略了。

造成这个现象的原因我们是在数据模板中设置的Label 的Grid.Row 和Grid.Column ,Label 控件并不是Grid的直接子元素,所以指定的行和列并没有起效果。

我们可以从ItemsControl 可视树中看到,Grid的直接子元素是ContentPresenter,而Lable 控件是ContentPresenter 的子元素。

那么我们应该做的是设置ContentPresenterGrid.RowGrid.Column 属性,而不是Label的。我们可以通过重写ItemsControl.PrepareContainerForItemOverride 方法来实现它。在这个方法中准备指定的元素以显示指定项,它会在收到要显示的项(比如本例中的ContentPresenter )和已经包含的内容(比如本例中的ChessPiece 实例)的时候调用。我们在这个方法中为ChessPiece 实例绑定行和列到ContentPresenter 。

public class GridBasedItemsControl : ItemsControl
    {
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
 
            ContentPresenter cp = element as ContentPresenter;
 
            if ((cp != null) && (item != null))
            {
                BindingOperations.SetBinding(cp, Grid.RowProperty, new Binding { Source = item, Path = new PropertyPath("Row")});
                BindingOperations.SetBinding(cp, Grid.ColumnProperty, new Binding { Source = item, Path = new PropertyPath("Column") });
            }
 
        }
    }


上面的代码新建了一个继承自ItemsControlGridBasedItemsControl类,并重写了PrepareContainerForItemOverride 以实现行和列的绑定。为了将绑定应用,我们需要将最开始XAML代码中Window下的根元素ItemsControl改为GridBasedItemsControl

<local:GridBasedItemsControl ItemsSource="{Binding ChessPieces}" Height="500" Width="500">
       ...... 
</local:GridBasedItemsControl>

原文地址:https://wpf.2000things.com/2011/12/12/448-data-binding-elements-in-a-collection-to-a-grid-part-i/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值