开发者

WPF ListView selection issue with CheckBox

I have a WPF ListView control for which I am dynamically creating columns. One of the columns happens to be a CheckBox column. When the user directly clicks on the CheckBox the ListView's SelectedItem is not changed. Had the checkbox been declared in XAML I would have added handling for the Click event to manually set the selection. However, I'm stumped since it's a dynamic column.

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

The converter takes in an object that has Properties associated with it, there is a name/value pair that can be referenced through indexers.

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

So, my question is how do I dymaically create a CheckBox that will cause the ListView row to be select when the user clicks on the CheckBox.

Thanks!

EDIT:

This question are similar, but doesn't have the dynamic piece: WPF ListView SelectedItem is null


One way of solving this is to create a 'ChildSelectionCompatibleListBoxItem' which derives from 'ListBoxItem' and manually handle selection in the PreviewMouseDown/Up events. Note that its get trickier when you are using SelectionMode.Extended

Another way is to create a derived ListBoxSelectionCompatibleCheckBox which 'escapes' mouse events when the parent ListBoxItem is not yet selected.


I come up with a solution that seems to work for the current implementation. The change is rooted in handling the click event of the checkbox and then setting the parent ListViewItem to 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 },
} );

In the event handler I call a new extension method to find the ListViewItem that the checkbox lives in. Then if it found the LiveViewItem I just have to tell it to be selected. This should work with multiple selection or single selection in my case. EDIT: NVM has pointed out that this will not work for multiple selections which is absolutely correct!

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

Here is the extension method that looks up the chain for a parent of the specified type.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜