WPF中的复选框网格

时间:2010-12-20 15:19:25

标签: wpf grid itemscontrol

我有一个WPF UserControl的datacontext绑定到这样的类:

public class CheckBoxGridViewModel
{
  public List<List<bool>> Checkboxes {get; set;}
}

我希望它显示一个复选框网格。我假设我可以使用Itemscontrol,但不知道如何使用每行的动态列集来完成它。

This question似乎回答了我的问题,但答案没有给出示例,我无法想出如何写出来。

所以问题是,如何编写xaml以显示Checkboxes属性的复选框,以便它们排成一个漂亮的网格?

外部列表是每一行,内部列表是行的每一列。

4 个答案:

答案 0 :(得分:3)

目前尚不清楚您是否期望每个内部列表具有相同的大小,但如果它们是您可以使用简单的设置。使用具有单行/列的嵌套ItemsControls UniformGrids将为您提供均匀分布并自动处理任何大小的集合,而无需像Grid一样设置行和列定义:

<ItemsControl ItemsSource="{Binding Checkboxes}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <ItemsControl ItemsSource="{Binding}">
        <ItemsControl.ItemTemplate>
          <DataTemplate>
            <CheckBox IsChecked="{Binding}"/>
          </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsPanelTemplate>
          <UniformGrid Rows="1"/>
        </ItemsPanelTemplate>
      </ItemsControl>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <UniformGrid Columns="1"/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>

答案 1 :(得分:2)

this question。 Jobi Joy的答案将让您呈现2D列表,但Binding将不起作用,因此您无法编辑您的值。

为了能够绑定值,您可以使用像这样的辅助类

public static class BindableListHelper
{
    public static List<List<Ref<T>>> GetBindable2DList<T>(List<List<T>> list)
    {
        List<List<Ref<T>>> refInts = new List<List<Ref<T>>>();

        for (int i = 0; i < list.Count; i++)
        {
            refInts.Add(new List<Ref<T>>());
            for (int j = 0; j < list[i].Count; j++)
            {
                int a = i;
                int b = j;
                refInts[i].Add(new Ref<T>(() => list[a][b], z => { list[a][b] = z; }));
            }
        }
        return refInts;
    }
}

此方法使用此Ref类

public class Ref<T> 
{
    private readonly Func<T> getter; 
    private readonly Action<T> setter;
    public Ref(Func<T> getter, Action<T> setter) 
    { 
        this.getter = getter; 
        this.setter = setter; 
    }
    public T Value { get { return getter(); } set { setter(value); } } 
}

然后您可以使用

为ItemsControl设置ItemsSource
itemsControl.ItemsSource = BindableListHelper.GetBindable2DList<bool>(Checkboxes);

并且编辑工作

使用与我链接的问题中的 Jobi Joy 相同的代码,您可以将DataTemplate_Level2中的Button更改为CheckBox并将IsChecked绑定为Value(因为它将指向Ref类)否则)

<Window.Resources>
    <DataTemplate x:Key="DataTemplate_Level2">
        <CheckBox IsChecked="{Binding Path=Value}" Height="15" Width="15" Margin="2"/>
    </DataTemplate>
    <DataTemplate x:Key="DataTemplate_Level1">
        <ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </DataTemplate>
</Window.Resources>
<StackPanel>
    <Border HorizontalAlignment="Left" BorderBrush="Black" BorderThickness="2">
        <ItemsControl x:Name="itemsControl" ItemTemplate="{DynamicResource DataTemplate_Level1}"/>
    </Border>
</StackPanel>

如果没有为CheckBox设置Content属性,它将看起来像这样

alt text

答案 2 :(得分:2)

您可以考虑创建一个公开RowColumnValue属性的类,并绑定到这些属性的集合。这允许您使用您选择的方法分配行和列位置,并且网格中的布局非常简单(当您理解ItemsControl如何使用其ItemsPanelItemContainerStyle属性时):

      <ItemsControl ItemsSource="{Binding Checkboxes}">
        <ItemsControl.ItemTemplate>
          <DataTemplate>
            <CheckBox IsChecked="{Binding Value, Mode=TwoWay}"/>
          </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
          <Grid DockPanel.Dock="Top">
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="20"/>
              <ColumnDefinition Width="20"/>
              <ColumnDefinition Width="20"/>
              <ColumnDefinition Width="20"/>
              <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
              <RowDefinition Height="20"/>
              <RowDefinition Height="20"/>
              <RowDefinition Height="20"/>
              <RowDefinition Height="20"/>
              <RowDefinition Height="20"/>
              <RowDefinition Height="20"/>
            </Grid.RowDefinitions> 
            </Grid>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
          <Style TargetType="ContentPresenter">
            <Setter Property="Grid.Row" Value="{Binding Row}"/>
            <Setter Property="Grid.Column" Value="{Binding Column}"/>
          </Style>
        </ItemsControl.ItemContainerStyle>
      </ItemsControl>

答案 3 :(得分:0)

您希望这个网格如何排列?这将影响要使用的ItemsControl.ItemsPanel。一些想法...

使用UniformGrid或WPF Toolkit WrapPanel。