2010-12-20 29 views
5

Mam DataContext WPF UserControl jest przywiązany do klasy tak:Siatka pól wyboru w WPF

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

chcę, aby wyświetlić siatkę wyboru. Zakładam, że mogę użyć ItemScontrol, ale nie wiem dokładnie, jak to zrobić z dynamicznym zestawem kolumn dla każdego wiersza.

This question wydaje się odpowiadać na moje, z wyjątkiem odpowiedzi nie podałem przykładu i nie mogę wymyślić, jak to napisać.

Pytanie brzmi, w jaki sposób powinienem napisać xaml, aby wyświetlić pola wyboru z właściwości Checkboxes, tak aby były ułożone w ładną siatkę?

Zewnętrzna lista będzie w każdym rzędzie, a wewnętrzna lista będzie każdą kolumną rzędu.

+0

ktoś próbuje zakodować Tic Tac Toe? : D – David

Odpowiedz

2

Zobacz this question. Odpowiedź Jobi Joy pozwoli ci przedstawić listę 2D, ale bindowanie nie będzie działać, więc nie możesz edytować swoich wartości.

Aby móc powiązać wartości można użyć klasy pomocnika jak ten

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; 
    } 
} 

tej metodzie używa tej klasy 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); } } 
} 

Następnie można ustawić ItemsSource do ItemsControl z

itemsControl.ItemsSource = BindableListHelper.GetBindable2DList<bool>(Checkboxes); 

i edycja powinna zadziałać

Stosując ten sam kod jak Jobi Joy od pytania I połączone, można zmienić przycisk DataTemplate_Level2 do wyboru i wiążą IsChecked za to cenić zamiast (ponieważ będzie to wskazywać na klasę Ref inaczej)

<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> 

Bez ustawienie właściwości zawartości dla CheckBox będzie to wyglądać mniej więcej tak

alt text

0

Jak dokładnie chcesz to zorganizował siatki? Wpłynie to na użycie ItemsControl.ItemsPanel. Kilka pomysłów ...

Użyj UniformGrid lub WPF Toolkit WrapPanel.

+0

Zobacz edytowane pytanie, dziękuję za pomoc – Jose

2

Można rozważyć utworzenie klasy, która ujawnia właściwości: , Column i Value i powiązanie z ich kolekcją. To pozwala przypisać wierszy i kolumn stanowisk metodą wyboru, a układ w sieci jest bardzo proste (po zrozumieniu jak ItemsControl używa jej ItemsPanel i ItemContainerStyle właściwości, oczywiście):

 <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

Nie jest jasne jeśli spodziewasz się, że każda wewnętrzna lista będzie tego samego rozmiaru, ale jeśli będziesz mogła użyć prostej konfiguracji.Korzystanie z zagnieżdżonych ItemsControls pojedynczy wiersz/kolumna UniformGrids daje równomierną dystrybucję i automatycznie obsługiwać zbiory dowolnej wielkości bez konieczności Row konfiguracji i definicji kolumn jak z siatką:

<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> 
+0

+1, to lepszy sposób prezentacji niż moja odpowiedź. –

+0

Dzięki za tę odpowiedź, bardzo mi to pomogło! Jest jeden błąd, brakuje ci dla , co powoduje wyjątek :-) – Mischo5500