Multiselect Listview с флажком выбора всех. Datatrigger на связанной собственности

У меня есть представление списка с видом сетки, которая имеет два столбца. Первый столбец содержит флажки, связанные с выбранным свойством listviewitem, второй столбец - текст. В заголовке для столбца флажков у меня есть флажок, который я хочу функционировать как кнопка выбора / отмены выбора всех. Я использовал для этого триггеры данных, но это работает только тогда, когда я удаляю привязку между флажками и выбранным свойством. Могу ли я использовать триггер данных для установки связанного свойства?

Скриншот

отделенный код

namespace ListviewWCheckboxes
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        List<string> listItems = new List<string>() { "foo", "bar", "blah" };
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            pdflistView.ItemsSource = listItems;
        }
    }
}

XAML

<Window x:Class="ListviewWCheckboxes.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ListviewWCheckboxes"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        Loaded="Window_Loaded">
    <Grid>
        <ListView x:Name="pdflistView" HorizontalAlignment="Left" Height="300" Margin="5" VerticalAlignment="Top" Width="240"
                      SelectionMode="Extended"
                      >
            <ListView.View>
                <GridView>
                    <GridViewColumn>
                        <GridViewColumn.Header>
                            <CheckBox x:Name="ckbxSelectAll"/>
                        </GridViewColumn.Header>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding Path=IsSelected, 
                                                RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}, Mode=FindAncestor},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
                                    <CheckBox.Style>
                                        <Style TargetType="CheckBox">
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding ElementName=ckbxSelectAll, Path=IsChecked}" Value="True">
                                                    <Setter Property="IsChecked" Value="True" />
                                                </DataTrigger>
                                                <DataTrigger Binding="{Binding ElementName=ckbxSelectAll, Path=IsChecked}" Value="False">
                                                    <Setter Property="IsChecked" Value="False" />
                                                </DataTrigger>
                                            </Style.Triggers>
                                        </Style>
                                    </CheckBox.Style>

                                </CheckBox>
                                <DataTemplate.Triggers>

                                </DataTemplate.Triggers>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>

                    </GridViewColumn>
                    <GridViewColumn Header="Pdf" DisplayMemberBinding="{Binding}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

3 ответа

Используя предложение AjS, я придумал это решение.

Я также смог придумать решение, которое детализировало визуальное дерево списка, пока не получил VirtualizingStackPanel, который содержит все элементы ListviewItems, и прошел через них, устанавливая свойство IsSelected, но это кажется более чистым.

XAML

 <Window x:Class="ListviewWCheckboxes.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ListviewWCheckboxes"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ListView x:Name="pdflistView" HorizontalAlignment="Left" Height="300" Margin="5" VerticalAlignment="Top" Width="240"
                      SelectionMode="Extended" ItemsSource="{Binding Path=listItems}">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="IsSelected" Value="{Binding is_Selected}"/>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.View>
                <GridView>
                    <GridViewColumn>
                        <GridViewColumn.Header>
                            <CheckBox x:Name="ckbxSelectAll" Checked="ckbxSelectAll_Checked" Unchecked="ckbxSelectAll_Checked"/>
                        </GridViewColumn.Header>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding is_Selected}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Pdf" DisplayMemberBinding="{Binding Path=text}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

код

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;

namespace ListviewWCheckboxes
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public ObservableCollection<someobjects> listItems { get; set; } = new ObservableCollection<someobjects>();

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            listItems.Add(new someobjects("foo"));
            listItems.Add(new someobjects("bar"));
            listItems.Add(new someobjects("blah"));
        }

        private void ckbxSelectAll_Checked(object sender, RoutedEventArgs e)
        {
            foreach (someobjects item in listItems)
            {
                item.is_Selected = (bool)((CheckBox)sender).IsChecked;
            }
        }

        public class someobjects : INotifyPropertyChanged
        {
            private string _text;

            public string text
            {
                get { return _text; }
                set { _text = value; OnPropertyChanged(); }
            }

            private bool _is_Selected;

            public bool is_Selected
            {
                get { return _is_Selected; }
                set { _is_Selected = value; OnPropertyChanged(); }
            }

            public someobjects(string t)
            {
                text = t;
                is_Selected = false;
            }

            public event PropertyChangedEventHandler PropertyChanged;

            protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
            {
                var handler = PropertyChanged;
                if (handler != null)
                    handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Для всех, кто интересуется вторым решением, которое я упомянул, это событие должно быть прикреплено к отмеченным и непроверенным событиям флажка selectall

private void ckbxSelectAll_Checked(object sender, RoutedEventArgs e)
    {
        DockPanel dp = FindVisualChild<DockPanel>(pdflistView, 0);
        ScrollContentPresenter scp = FindVisualChild<ScrollContentPresenter>(dp, 1);
        VirtualizingStackPanel vsp = FindVisualChild<VirtualizingStackPanel>(scp, 0);

        foreach (ListViewItem item in vsp.Children)
        {
            item.IsSelected = (bool)((CheckBox)sender).IsChecked;
        }
    }

    private static T FindVisualChild<T>(UIElement element, int childindex) where T : UIElement
    {
        UIElement child = element;
        while (child != null)
        {
            T correctlyTyped = child as T;
            if (correctlyTyped != null)
            {
                return correctlyTyped;
            }

            child = VisualTreeHelper.GetChild(child, childindex) as UIElement;
        }
        return null;
    }

Я считаю, что лучший способ реализовать это - создать свойство IsSelected для вашего класса и связать его с флажком (IsChecked) и списком (isSelected). Обработайте событие флажка заголовка и вручную переключите свойство IsSelected элементов в коллекции, чтобы флажки и элементы списка были обновлены. Пожалуйста, дайте мне знать, если у вас есть другие вопросы

Другие вопросы по тегам