CheckBox ListView SelectedValues DependencyProperty Binding

Posted by Ristogod on Stack Overflow See other posts from Stack Overflow or by Ristogod
Published on 2011-01-08T05:46:26Z Indexed on 2011/01/08 5:53 UTC
Read the original article Hit count: 443

I am writing a custom control that is a ListView that has a CheckBox on each item in the ListView to indicate that item is Selected. I was able to do so with the following XAML.

<ListView x:Class="CheckedListViewSample.CheckBoxListView"
          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">
    <ListView.Style>
        <Style TargetType="{x:Type ListView}">
            <Setter Property="SelectionMode" Value="Multiple" />
            <Style.Resources>
                <Style TargetType="ListViewItem">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ListViewItem">
                                <Border BorderThickness="{TemplateBinding Border.BorderThickness}"
                                        Padding="{TemplateBinding Control.Padding}"
                                        BorderBrush="{TemplateBinding Border.BorderBrush}"
                                        Background="{TemplateBinding Panel.Background}"
                                        SnapsToDevicePixels="True">
                                    <CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}">
                                        <CheckBox.Content>
                                            <ContentPresenter Content="{TemplateBinding ContentControl.Content}"
                                                              ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
                                                              HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
                                                              VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
                                                              SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                                        </CheckBox.Content>
                                    </CheckBox>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Style.Resources>
        </Style>
    </ListView.Style>
</ListView>

I however am trying to attempt one more feature. The ListView has a SelectedItems DependencyProperty that returns a collection of the Items that are checked. However, I need to implement a SelectedValues DependencyProperty. I also am implementing a SelectedValuesPath DependencyProperty. By using the SelectedValuesPath, I indicate the path where the values are found for each selected item. So if my items have an ID property, I can specify using the SelectedValuesPath property "ID". The SelectedValues property would then return a collection of ID values. I have this working also using this code in the code-behind:

using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;

namespace CheckedListViewSample
{
    /// <summary>
    /// Interaction logic for CheckBoxListView.xaml
    /// </summary>
    public partial class CheckBoxListView : ListView
    {
        public static DependencyProperty SelectedValuesPathProperty =
            DependencyProperty.Register("SelectedValuesPath", 
            typeof(string),
            typeof(CheckBoxListView),
            new PropertyMetadata(string.Empty, null));

        public static DependencyProperty SelectedValuesProperty =
            DependencyProperty.Register("SelectedValues", 
            typeof(IList), 
            typeof(CheckBoxListView),
            new PropertyMetadata(new List<object>(), null));

        [Category("Appearance")]
        [Localizability(LocalizationCategory.NeverLocalize)]
        [Bindable(true)]
        public string SelectedValuesPath
        {
            get
            {
                return ((string)(base.GetValue(CheckBoxListView.SelectedValuesPathProperty)));
            }
            set
            {
                base.SetValue(CheckBoxListView.SelectedValuesPathProperty, value);
            }
        }

        [Bindable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Category("Appearance")]
        public IList SelectedValues
        {
            get
            {
                return ((IList)(base.GetValue(CheckBoxListView.SelectedValuesPathProperty)));
            }
            set
            {
                base.SetValue(CheckBoxListView.SelectedValuesPathProperty, value);
            }
        }

        public CheckBoxListView()
            : base()
        {
            InitializeComponent();
            base.SelectionChanged += new SelectionChangedEventHandler(CheckBoxListView_SelectionChanged);     
        }

        private void CheckBoxListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            List<object> values = new List<object>();

            foreach (var item in SelectedItems)
            {
                if (string.IsNullOrWhiteSpace(SelectedValuesPath))
                {
                    values.Add(item);
                }
                else
                {
                    try
                    {
                        values.Add(item.GetType().GetProperty(SelectedValuesPath).GetValue(item, null));
                    }
                    catch { }
                }
            }

            base.SetValue(CheckBoxListView.SelectedValuesProperty, values);

            e.Handled = true;
        }
    }
}

My problem is that my binding only works one way right now. I'm having trouble trying to figure out how to implement my SelectedValues DependencyProperty so that I could Bind a Collection of values to it, and when the control is loaded, the CheckBoxes are checked with items that have values that correspond to the SelectedValues.

I've considered using the PropertyChangedCallBack event, but can't quite figure out how I could write that to achieve my goal.

I'm also unsure of how I find the correct ListViewItem to set it as Selected.

And lastly, if I can find the ListViewItem and set it to be Selected, won't that fire my SelectionChanged event each time I set a ListViewItem to be Selected?

© Stack Overflow or respective owner

Related posts about wpf

Related posts about listview