0

I have a WPF application that utilizes a ListView with a bound source. Each ListViewItem is a custom View with controls bound to properties of the underlying data. I'm using the Extended SelectionMode and would like a way for all selected items to have the properties modified when one item is interacted with while multiple are selected.

Example Usage: * Select all the items in my list. * Click on "Property 1" for one of the items. * Have all item's Property 1 flag set to true.

Is there a way to accomplish this? I can think of a few hacks but nothing that feels clean.

Example Code:

MainWindow.xaml


    <Window.DataContext>
        <ViewModels:MainWindowViewModel/>
    </Window.DataContext>

    <ListView x:Name="MyList" Height="auto" Width="auto" Grid.Row="1" ItemsSource="{Binding ListSource}">
        <ListView.ItemTemplate>
            <DataTemplate x:Name="ItemTemplate" DataType="ViewModels:FlagCollectionViewModel">
                <Views:FlagCollectionView />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

FlagCollectionViewModel.xaml:

    <UserControl x:Class="WpfApp2.Views.FlagCollectionView"
                 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" 
                 xmlns:local="clr-namespace:WpfApp2.Views"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800"
                 BorderBrush="Black"
                 BorderThickness="1">
        <UserControl.Resources>
            <Style TargetType="CheckBox">
                <Setter Property="Width" Value="auto"/>
                <Setter Property="Height" Value="auto"/>
                <Setter Property="Margin" Value="3"/>
            </Style>
        </UserControl.Resources>

        <Grid Width="auto" Height="auto">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition Width="auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>

            <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding Name}"/>
            <CheckBox Grid.Row="1" Grid.Column="0" IsChecked="{Binding Flag1}">Property 1</CheckBox>
            <CheckBox Grid.Row="1" Grid.Column="1" IsChecked="{Binding Flag2}">Property 2</CheckBox>
            <CheckBox Grid.Row="1" Grid.Column="2" IsChecked="{Binding Flag3}">Property 3</CheckBox>
        </Grid>
    </UserControl>

MainWindowViewModel:


    public class MainWindowViewModel
    {
        public MainWindowViewModel()
        {
            _ListSource = new ObservableCollection<FlagCollectionViewModel>();
            _ListSource.Add(new FlagCollectionViewModel("Instance 1"));
            _ListSource.Add(new FlagCollectionViewModel("Instance 2"));
            _ListSource.Add(new FlagCollectionViewModel("Instance 3"));
            _ListSource.Add(new FlagCollectionViewModel("Instance 4"));
        }

        private ObservableCollection<FlagCollectionViewModel> _ListSource = null;
        public ObservableCollection<FlagCollectionViewModel> ListSource => _ListSource;
    }

FlagCollectionViewModel.cs

    public class FlagCollectionViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public FlagCollectionViewModel(string NameIn)
        {
            _Name = NameIn;
        }

        private string _Name;
        public string Name => _Name;

        private bool _Flag1, _Flag2, _Flag3;
        public bool Flag1
        {
            get => _Flag1;
            set => SetFlag(ref _Flag1, value, nameof(Flag1));
        }

        public bool Flag2
        {
            get => _Flag2;
            set => SetFlag(ref _Flag2, value, nameof(Flag2));
        }

        public bool Flag3
        {
            get => _Flag3;
            set => SetFlag(ref _Flag2, value, nameof(Flag3));
        }

        private void SetFlag(ref bool Target, bool Value, string PropertyName)
        {
            Target = Value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
            System.Diagnostics.Debug.Print(Name + ": " + Flag1 + ", " + Flag2 + ", " + Flag3);
        }
    }
Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
GiantBen
  • 51
  • 4
  • Your question is too broad. That said, a good solution will require identifying all selected items. Then you can perform whatever operation you like on them. See marked duplicate. You will probably want to also monitor changes to the property or properties in question, so that you can react to changes in one item, to be applied to all other selected items. – Peter Duniho Jan 25 '20 at 00:51
  • What specifics are missing that could help narrow the problem? – GiantBen Jan 26 '20 at 01:05
  • _"What specifics are missing"_ -- your actual attempt to solve the problem. Questions having the form _"Is there a way to accomplish this?"_ are inherently too broad, as there are numerous, often unlimited numbers of, answers that _could_ solve the problem. It should be clear to potential answerers which of the many different alternatives would satisfy you, and the best way is for you to decide on a particular approach, attempt to implement it, and then ask a question only if you have some _specific_ difficulty with that implementation. – Peter Duniho Jan 26 '20 at 05:49

0 Answers0