【问题标题】:Grid of Checkboxes in WPFWPF中的复选框网格
【发布时间】:2011-05-28 07:40:52
【问题描述】:

我有一个 WPF UserControl 的数据上下文绑定到这样的类:

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

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

This question 似乎回答了我的问题,只是答案没有给出示例,我不知道如何写出来。

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

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

【问题讨论】:

  • 有人尝试编写井字游戏? :D

标签: wpf grid itemscontrol


【解决方案1】:

不清楚您是否希望每个内部列表的大小相同,但如果是,您可以使用简单的设置。将嵌套的 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>

【讨论】:

  • 感谢您的回答,它对我帮助很大!有一个错误,您缺少 并导致异常:-)
【解决方案2】:

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

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

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 属性,它将看起来像这样

【讨论】:

    【解决方案3】:

    您可以考虑创建一个公开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>
    

    【讨论】:

      【解决方案4】:

      您希望这个网格如何排列?这将影响使用哪个 ItemsControl.ItemsPanel。几个想法...

      使用 UniformGrid 或 WPF 工具包 WrapPanel。

      【讨论】:

        猜你喜欢
        • 2013-09-28
        • 1970-01-01
        • 2020-08-26
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        • 1970-01-01
        • 2013-07-31
        • 2015-08-05
        相关资源
        最近更新 更多