使用CheckBox的WPF ListView选择问题

时间:2010-08-18 15:25:12

标签: c# .net wpf

我有一个WPF ListView控件,我正在动态创建列。其中一列恰好是CheckBox列。当用户直接单击CheckBox时,ListView的SelectedItem不会更改。如果在XAML中声明了复选框,我会为Click事件添加处理以手动设置选择。但是,我很难过,因为它是一个动态的专栏。

<ListView
    SelectionMode="Single"
    ItemsSource="{Binding Documents}"                    
    View="{Binding Converter={local:DocumentToGridViewConverter}}" />

转换器接受一个具有与之关联的Properties的对象,有一个名称/值对可以通过索引器引用。

public class DocumentToGridViewConverter : MarkupExtension, IValueConverter
{
    private static DocumentToGridViewConverter mConverter;

    public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
    {
        GridView gridView = null;

        Document document = value as Document;
        if( document != null )
        {
            // Create a new grid view.
            gridView = new GridView();

            // Add an isSelected checkbox complete with binding.
            var checkBox = new FrameworkElementFactory( typeof( CheckBox ) );
            gridView.Columns.Add( new GridViewColumn
            {
                Header = string.Empty, // Blank header
                CellTemplate = new DataTemplate { VisualTree = checkBox  },
            } );

            // Add the rest of the columns from the document properties.
            for( int index = 0; index < document.PropertyNames.Length; index++ )
            {
                gridView.Columns.Add( new GridViewColumn
                {
                    Header = document.PropertyNames[index];
                    DisplayMemberBinding = new Binding(
                        string.Format( "PropertyValues[{0}]", index ) )
                } );
            }
        }

        return gridView;
    }

    public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
    {
        throw new NotImplementedException();
    }

    public override object ProvideValue( IServiceProvider serviceProvider )
    {
        if( mConverter == null )
        {
            mConverter = new DocumentToGridViewConverter();
        }
        return mConverter;
    }
}

所以,我的问题是我如何动态创建一个CheckBox,当用户点击CheckBox时会导致ListView行被选中。

谢谢!

修改

这个问题很相似,但没有动态篇幅:WPF ListView SelectedItem is null

2 个答案:

答案 0 :(得分:0)

解决此问题的一种方法是创建一个'ChildSelectionCompatibleListBoxItem',它从'ListBoxItem'派生并手动处理PreviewMouseDown / Up事件中的选择。请注意,当您使用SelectionMode.Extended

时,它会变得更加棘手

另一种方法是创建派生的ListBoxSelectionCompatibleCheckBox,当尚未选择父ListBoxItem时,它会“转义”鼠标事件。

答案 1 :(得分:0)

我想出了一个似乎适用于当前实现的解决方案。更改的根源在于处理复选框的click事件,然后将父ListViewItem设置为selected。

FrameworkElementFactory checkBox = new FrameworkElementFactory( typeof(CheckBox) );
checkBox.AddHandler( CheckBox.ClickEvent, new RoutedEventHandler( OnCheckBoxClick ) );
gridView.Columns.Add( new GridViewColumn
{
    Header = string.Empty,
    CellTemplate = new DataTemplate { VisualTree = checkBox },
} );

在事件处理程序中,我调用一个新的扩展方法来查找复选框所在的ListViewItem。然后,如果它找到了LiveViewItem,我只需要告诉它被选中。 在我的情况下,这应该适用于多项选择或单项选择。 编辑: NVM已经指出这不适用于绝对正确的多项选择!

private void OnCheckBoxClick( object sender, RoutedEventArgs e )
{
    ListViewItem item = ((CheckBox)sender).FindParent<ListViewItem>();
    if( item != null )
    {
        item.IsSelected = true;
    }
}

以下是查找指定类型父级链的扩展方法。

public static class DependencyObjectExtensions
{
    public static TItem FindParent<TItem>( this DependencyObject dependencyObject )
        where TItem : class
    {
        TItem parent = null;

        DependencyObject possibleParent = dependencyObject;
        while( parent == null && possibleParent != null )
        {
            parent = possibleParent as TItem;
            possibleParent = VisualTreeHelper.GetParent( possibleParent );
        }

        return parent;
    }
}