views:

236

answers:

2

Hi there. I already read many examples on extending ListViews with checkboxes bound with IsSelected. But I want something more.

I want a seperation between the checked and selected state, so i get a ListBox that has a single selected item, but can have multiple checked items. Unfortunately ListViewItem does not have a property for checked and I dont see a possibility to get the ListView to work with a custom CheckableListViewItem.

Of course i could use a List of objects with a checked property as ItemSource, but I dont think thats a good way to go. Checked or not is a matter of the list or item-container, not of the object listed in it. Beside that I dont want all my classes like user, role, group to have counterparts like checkableUser, checkableRole and checkableGroup.

The behaviour i want can be easyly accomblished for the UI with a

<DataTemplate x:Key="CheckBoxCell">
   <StackPanel Orientation="Horizontal">
      <CheckBox />
   </StackPanel>
</DataTemplate>

and a

<GridViewColumn CellTemplate="{StaticResource CheckBoxCell}" Width="30"/>

But without a binding on the checkbox i cant check if it is checked or not.

Is there any way to accomplish something like that? The perfect solution for me would be to have listView1.SelectedItem, listView1.CheckedItems and maybe a listView1.UncheckedItems and of course listView1.CheckItem and listView1.UncheckItem.

Thanks for any help.

+1  A: 

In order to do this, you will have to create a custom ListBox and custom ListBoxItem controls to use within your application. Otherwise, you would have to add it to the items in your lists as a generic object ICheckable<T> (where T is User or Role) and have an ICheckableCollection<ICheckable<T>> for your items instead of adding a checkable to your model objects.

Jeff Wain
Just to be correct, im talking about ListView and ListViewItem, but its almost the same. Your right with the customs classes, and I think it wouldnt be that complex. But to create a ListView.CheckedItems, i need to iterate through the containers to look for checked ones and I dont see a way to do that. Iterating through items and use GetContainerForItem works only for Items that are of type DependencyObject. Any clue?
Marks
+1  A: 

Ok, I got it. Wasn't much to do, but becouse I'm new to the whole WPF stuff, its been some work to figure out. Here is the solution:

public class CheckableListViewItem : ListViewItem
{
    [Category("Appearance")]
    [Bindable(true)]
    public bool IsChecked { get; set; }
}

public class CheckableListView : ListView
{
    public IList CheckedItems
    {
        get
        {
            List<object> CheckedItems = new List<object>();
            for (int i=0;i < this.Items.Count; ++i)
            {
                if ((this.ItemContainerGenerator.ContainerFromIndex(i) as CheckableListViewItem).IsChecked)
                    CheckedItems.Add(this.Items[i]);
            }
            return CheckedItems;
        }
    }
    public bool IsChecked(int index)
    {
        if (index < this.Items.Count) return (this.ItemContainerGenerator.ContainerFromIndex(index) as CheckableListViewItem).IsChecked;
        else throw new IndexOutOfRangeException();
    }
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        if (item is CheckableListViewItem) return true;
        else return false;
    }
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new CheckableListViewItem();
    }
}

Insert into your XAML under Window.Resources (clr = my class namespace):

<DataTemplate x:Key="CheckBoxCell">
    <StackPanel Orientation="Horizontal">
        <CheckBox IsChecked="{Binding Path=IsChecked, 
            RelativeSource={RelativeSource FindAncestor, 
            AncestorType={x:Type clr:CheckableListViewItem}}}" />
    </StackPanel>
</DataTemplate>

And this as your CheckableListView:

<clr:CheckableListView SelectionMode="Single" [...] >
        <ListView.View>
            <GridView>
                <GridViewColumn CellTemplate="{StaticResource CheckBoxCell}" 
                      Width="30"/>
                [...]
            </GridView>
        </ListView.View>
    </clr:CheckableListView>

Maybe this helps someone with the same problem.

Marks