绑定列表<list <myclass>&gt;到网格中的单元格</list <myclass>

时间:2013-02-01 02:21:06

标签: wpf xaml

以下是我的相关帖子的一些背景信息: How to databind using to a 2d array of objects of different types

所以我有一个:

List<List<FarmyardSpace>>

我希望将其表示为网格单元格中的按钮。我不能像在相关帖子中那样使用UniformGrid,因为我需要在Grid中定义单元格的大小。理想情况下,我不想在我的数据中定义行和列字段(虽然这可能是由ViewModel以某种方式处理的?前几天刚刚开始学习这些东西,我仍然围绕着WPF和MVVM)

这是我的最新尝试无效(实际上会引发异常),在这个特定的例子中,我依赖于FarmyardSpaces上存在的Column和Row属性:

<ItemsControl ItemsSource="{Binding FarmyardGrid}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding}">
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="15"/>
                            <RowDefinition />
                            <RowDefinition Height="15"/>
                            <RowDefinition />
                            <RowDefinition Height="15"/>
                            <RowDefinition />
                            <RowDefinition Height="15"/>
                        </Grid.RowDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Grid.Row" Value="{Binding Row}"/>
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="15"/>
                    <ColumnDefinition />
                    <ColumnDefinition Width="15"/>
                    <ColumnDefinition />
                    <ColumnDefinition Width="15"/>
                    <ColumnDefinition />
                    <ColumnDefinition Width="15"/>
                    <ColumnDefinition />
                    <ColumnDefinition Width="15"/>
                    <ColumnDefinition />
                    <ColumnDefinition Width="15"/>
                </Grid.ColumnDefinitions>
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Grid.Column" Value="{Binding Column}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

我认为这部分不起作用的部分原因是外部ItemsControl包含的Items不是FarmyardSpaces而是List,因此它们没有要绑定的Column属性。我也尝试了内部ItemsControl中的RowDefinitions和ColumnDefinitions。这摆脱了异常,但也不起作用,对我来说似乎不对,特别是考虑到在外部ItemsControl中声明Columns的相关帖子中使用UniformGrid时有效的解决方案。

无论如何,我很感激任何帮助解决这个问题,提前谢谢!

1 个答案:

答案 0 :(得分:1)

如果您的收藏品上有属性,指明它们在网格中的位置,这显然是最简单的,这就是您现在设置的内容。如果没有,您可以使用转换器为您计算每个项目的索引,然后将其指定为行/列值 - 并且它在两个维度中的工作方式相同。这是基本的转换器:

public class ItemToIndexConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        object item = values.FirstOrDefault();
        IList collection = values.OfType<IList>().LastOrDefault();

        if (collection == null || item == null)
            return 0;

        return collection.IndexOf(item);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

和XAML的修改版本(减少到3x3)从父ItemsControl获取当前项目和完整集合以传递到转换器:

<ItemsControl ItemsSource="{Binding FarmyardGrid}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="15"/>
                                <RowDefinition />
                                <RowDefinition Height="15"/>
                            </Grid.RowDefinitions>
                        </Grid>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Grid.Row">
                            <Setter.Value>
                                <MultiBinding>
                                    <MultiBinding.Converter>
                                        <local:ItemToIndexConverter/>
                                    </MultiBinding.Converter>
                                    <Binding/>
                                    <Binding Path="ItemsSource"
                                             RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}"/>
                                </MultiBinding>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="15"/>
                    <ColumnDefinition />
                    <ColumnDefinition Width="15"/>
                </Grid.ColumnDefinitions>
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Grid.Column">
                <Setter.Value>
                    <MultiBinding>
                        <MultiBinding.Converter>
                            <local:ItemToIndexConverter/>
                        </MultiBinding.Converter>
                        <Binding/>
                        <Binding Path="ItemsSource"
                                 RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}"/>
                    </MultiBinding>
                </Setter.Value>
            </Setter>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>