1

I am still wrapping my head around this whole MVVM pattern but i thought i had a good grasp on it until i attempted to create a Checkbox column for my Gridview. I need the user to be able to select all items listed(via the header checkbox) or select the items listed individually. I databound the IsChecked property of my checkboxes to two boolean fields on my viewmodel. The checkbox on the cell template works as expected and fires the property changed event. The header does nothing. What am i missing here. Again this is still new to me so be gentle. Also if there is something i should be doing, or a better way to accomplish this...im all ears.

Thanks

XAML

 <UserControl x:Class="CheckBoxDemo.GridDemo"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <ListView ItemsSource="{Binding PersonList}">
        <ListView.View>
            <GridView>
                <GridViewColumn Width="50">
                    <GridViewColumn.HeaderTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsMainSelected}"/>
                        </DataTemplate>
                    </GridViewColumn.HeaderTemplate>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsSelected}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="100"></GridViewColumn>
            </GridView>
        </ListView.View>


    </ListView>
</Grid>

ViewModel

class GridDemoViewModel:INotifyPropertyChanged
{
    public List<Person> PersonList { get; private set; }
    // Fields...
    private bool _isMainSelected;

    public bool IsMainSelected
    {
        get { return _isMainSelected; }
        set
        {
            _isMainSelected = value;
            NotifyPropertyChanged("IsMainSelected");

        }
    }

    public GridDemoViewModel()
    {
        PersonList = new List<Person>();
        PersonList.Add(new Person { Name = "John"});
        PersonList.Add(new Person { Name = "Tom" });
        PersonList.Add(new Person { Name = "Tina" });
        PersonList.Add(new Person { Name = "Mary" });
        PersonList.Add(new Person { Name = "Mia"});
        PersonList.Add(new Person { Name = "Crystal" });


    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

Person Class

public class Person:INotifyPropertyChanged
{
    public string Name { get; set; }
    // Fields...
    private bool _isSelected;

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (_isSelected == value)
                return;
            _isSelected = value;
            NotifyPropertyChanged("IsSelected");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

1 Answer 1

2

The issue is that the GridViewColumn is not part of the Visual Tree. This means that it does not inherit the DataContext of the parent ListView. You have to find some other way of referencing the ViewModel. Check out Josh Smith's DataContextSpy which allows you to easily introduce an "artificially inherited" DataContext

<UserControl.Resources>
     <spy:DataContextSpy x:Key="Spy" />
</UserControl.Resources>

<DataTemplate>
   <CheckBox IsChecked="{Binding Source={StaticResource Spy} Path=DataContext.IsMainSelected}"/>
</DataTemplate>
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the link - I've tackled the same problem many times over the last couple of years but somehow missed this!
Thanks. This worked great. I used the simpler method of the three and added the data context to the app.resources.
Any suggestions on the right way to select all rows. Ive seen a couple of methods but the seem hacky and not as elegant as the MVVM pattern.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.