Search code examples
c#wpfcheckboxitemscontrolitemssource

Some items not showing up in ItemsControl via ItemsSource


I'm trying to get an ItemsControl, which contains a grid, to display 9 checkboxes with different properties. However, only three ever show up.

I have a checkbox model class which has four properties representing the checkboxs' content, grid.row/column, and isChecked properties. I then create nine of these in my viewmodel and add them to an ObservableCollection.

Next I bind the ItemsSource of my ItemsControl to the collection. Then, I add a checkbox control to the grid inside of the ItemsControl and bind the appropriate properties.

However, only the first three checkboxes are showing up and I have no idea why. I did verify via debugging that the collection being bound to does have the correct number of items.

Here's my CheckboxModel class:

public class CheckboxModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private bool _isChecked;
    public bool IsChecked
    {
        get { return _isChecked; }
        set { _isChecked = value; OnPropertyChanged("IsChecked"); }
    }

    private string _content;
    public string Content
    {
        get { return _content; }
        set { _content = value; OnPropertyChanged("Content"); }
    }

    private int _gridRow;
    public int GridRow
    {
        get { return _gridRow; }
        set { _gridRow = value; OnPropertyChanged("GridRow"); }
    }

    private int _gridColumn;
    public int GridColumn
    {
        get { return _gridColumn; }
        set { _gridColumn = value; OnPropertyChanged("GridColumn"); }
    }

    // Create the OnPropertyChanged method to raise the event
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

In my view model, I create a collection of these:

private ObservableCollection<CheckboxModel> _checkBoxList = new ObservableCollection<CheckboxModel>();
public ObservableCollection<CheckboxModel> CheckBoxList
{
    get
    {
        return _checkBoxList;
    }
    set
    {
        if (null != value)
        {
            _checkBoxList = value;
            OnPropertyChanged("CheckBoxList");
        }
    }
}

public void CreateCheckboxList()
{
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Latitude", GridRow = 0, GridColumn = 0  });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Longitude", GridRow = 1, GridColumn = 0 });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Altitude", GridRow = 2, GridColumn = 0 });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Depth", GridRow = 0, GridColumn = 1 });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Speed", GridRow = 1, GridColumn = 1 });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Heading", GridRow = 2, GridColumn = 1 });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Roll", GridRow = 0, GridColumn = 2 });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "Pitch", GridRow = 1, GridColumn = 2 });
    CheckBoxList.Add(new CheckboxModel { IsChecked = true, Content = "VOS", GridRow = 2, GridColumn = 2 }); 
}

And then finally here's my xaml:

<ItemsControl ItemsSource="{Binding CheckBoxList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="149.6*" />
                    <ColumnDefinition Width="149.6*" />
                    <ColumnDefinition Width="149.6*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="28*" />
                    <RowDefinition Height="28*" />
                    <RowDefinition Height="28*" />
                </Grid.RowDefinitions>
                <CheckBox Grid.Row="{Binding GridRow}"
                          Grid.Column="{Binding GridColumn}"
                          Margin="14,6,63,6"
                          VerticalAlignment="Center"
                          Content="{Binding Content}"
                          IsChecked="{Binding IsChecked}" />
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Here's what it looks like:

enter image description here

Here's what I want it to look like:

enter image description here


Solution

  • The problem is that a new Grid is created for each item in your ObservableCollection but you want a single Grid for all items.

    You could set the ItemsPanel of the ItemsControl to your Grid and use an ItemContainerStyle to set the Grid.Row and Grid.Column attached properties of each item container.

    This should work:

    <ItemsControl ItemsSource="{Binding CheckBoxList}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="149.6*" />
                        <ColumnDefinition Width="149.6*" />
                        <ColumnDefinition Width="149.6*" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="28*" />
                        <RowDefinition Height="28*" />
                        <RowDefinition Height="28*" />
                    </Grid.RowDefinitions>
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Grid.Row" Value="{Binding GridRow}" />
                <Setter Property="Grid.Column" Value="{Binding GridColumn}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <CheckBox Margin="14,6,63,6"
                              VerticalAlignment="Center"
                              Content="{Binding Content}"
                              IsChecked="{Binding IsChecked}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    enter image description here