1

我正在编写一个自定义控件,它是一个 ListView,在 ListView 中的每个项目上都有一个 CheckBox,以指示该项目已被选中。我能够使用以下 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>

但是,我正在尝试再尝试一项功能。ListView 有一个 SelectedItems DependencyProperty,它返回已检查项的集合。但是,我需要实现一个 SelectedValues DependencyProperty。我也在实现一个 SelectedValuesPath DependencyProperty。通过使用 SelectedValuesPath,我指明了为每个选定项目找到值的路径。因此,如果我的项目具有 ID 属性,我可以使用 SelectedValuesPath 属性“ID”来指定。SelectedValues 属性将返回 ID 值的集合。我也在代码隐藏中使用此代码进行此工作:

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

我的问题是我的绑定现在只能以一种方式工作。我在尝试弄清楚如何实现我的 SelectedValues DependencyProperty 以便我可以将一组值绑定到它时遇到了麻烦,并且在加载控件时,使用具有与 SelectedValues 对应的值的项目来检查 CheckBoxes。

我考虑过使用 PropertyChangedCallBack 事件,但不能完全弄清楚如何编写它来实现我的目标。

我也不确定如何找到正确的 ListViewItem 以将其设置为 Selected。

最后,如果我可以找到 ListViewItem 并将其设置为 Selected,那么每次我将 ListViewItem 设置为 Selected 时不会触发我的 SelectionChanged 事件吗?

4