我有一个WPF UserControl的datacontext绑定到这样的类:
public class CheckBoxGridViewModel
{
public List<List<bool>> Checkboxes {get; set;}
}
我希望它显示一个复选框网格。我假设我可以使用Itemscontrol,但不知道如何使用每行的动态列集来完成它。
This question似乎回答了我的问题,但答案没有给出示例,我无法想出如何写出来。
所以问题是,如何编写xaml以显示Checkboxes属性的复选框,以便它们排成一个漂亮的网格?
外部列表是每一行,内部列表是行的每一列。
答案 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设置ItemsSourceitemsControl.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属性,它将看起来像这样
答案 2 :(得分:2)
您可以考虑创建一个公开Row
,Column
和Value
属性的类,并绑定到这些属性的集合。这允许您使用您选择的方法分配行和列位置,并且网格中的布局非常简单(当您理解ItemsControl
如何使用其ItemsPanel
和ItemContainerStyle
属性时):
<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。