Datagrid multiselect checkbox set checked or unchecked mvvm

Kran2022 406 Reputation points
2023-02-24T08:15:37.83+00:00

Hi All: Morning

From my datagrid i have a col visible (string propery) checkbox for True or False, i would like slect multiple rows in the datagrid or selct all (ctrl + A )then from a checkbox set active

(checked = select selected rows)

(unchecked = un-select the selected rows)

I added below to the datagrid resource to allow multi selection:

<DataGrid.Resources>
<Style TargetType="DataGridRow"><Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</DataGrid.Resources>

Checkbox to set selected rows checked/un-checked:

<CheckBox Width="120" Name="cselectall" Content="Select All" Grid.Column="1" VerticalAlignment="Bottom" Margin="30,0,0,30"
	IsChecked="{Binding IsSelected,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right"/>

ViewModel:

private bool _isSelected;
public bool IsSelected
{
	get { return _isSelected; }
	set
	{
		_isSelected = value;
		OnPropertyChanged("SelectedItems");
	}
}

public ObservableCollection<Products> SelectedItems { get; }  = new ObservableCollection<Products>();

What am i missing here because when i slected multipl rows or selected all rows, by checking the box Name="cselectall" Content="Select All", its not triggering? thanks for your help

24022023

Product class:

  public class Products
    {

        public event PropertyChangedEventHandler PropertyChanged;

        string sysid;
        string mainproduct;
        string name;
        string visible;
        string nameicon;


        public string SysId
        {
            get { return sysid; }
            set { sysid = value; }
        }

        public string Mainproduct
        {
            get { return mainproduct; }
            set { mainproduct = value; }
        }
        public string Name
        {
            get { return name; }
            set { name = value; }
        }


        public string Visible
        {
            get { return visible; }
            set
            {
                visible = value;

            }
        }

                
        public string NameIcon
        {
            get { return nameicon; }
            set { nameicon = value; }
        }

        public PriceDetail PriceDetail { get; set; }

        public List<PriceDetail> Prices { get; set; } = new List<PriceDetail>();

     
}
Developer technologies Windows Presentation Foundation
Developer technologies C#
{count} vote

Accepted answer
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2023-02-27T17:43:17.8233333+00:00

    Hi,
    I use your old solution and add attached behavior for using SelectedItems of datagrid:

    <Window x:Class="WpfApp1.Window043"
            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:WpfApp043"
            mc:Ignorable="d"
            Title="Kran2022_230224" Height="450" Width="800">
      <Window.DataContext>
        <local:ProductPriceViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="2*"/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <DataGrid x:Name="datagrid" local:ProductPriceViewModel.AttProp="True"
                  ItemsSource="{Binding View}" AutoGenerateColumns="False">
          <DataGrid.Columns>
            <DataGridTextColumn Header="SystemPriceID" Binding="{Binding SysId}" Width="*" IsReadOnly="True"/>
            <DataGridTextColumn Header="MianProduct"   Binding="{Binding Mainproduct}" Width="*" IsReadOnly="True"/>
            <DataGridTextColumn Header="Name"   Binding="{Binding Name}" Width="*" IsReadOnly="True"/>
    
            <DataGridTemplateColumn Header="Visible"  Width="100" >
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <CheckBox IsChecked="{Binding Visible, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="Add"  Width="*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Button>Add</Button>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="Remove" Width="*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Button>Remove</Button>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
          </DataGrid.Columns>
        </DataGrid>
        <CheckBox Width="120"  
                  Content="Select All" 
                  Grid.Column="1" 
                  VerticalAlignment="Bottom" Margin="30,0,0,30"
                  IsChecked="{Binding IsSelected,UpdateSourceTrigger=PropertyChanged}" 
                  HorizontalAlignment="Right"/>
        <Button Grid.Row="1" Content="Load" Width="100" Margin="10" HorizontalAlignment="left"
                Command="{Binding Cmd}" CommandParameter="Load"/>
        <Button Grid.Row="1" Content="Clear" Width="100" Margin="10" HorizontalAlignment="Center"
                Command="{Binding Cmd}" CommandParameter="Clear"/>
        <Button Grid.Row="1" Content="Save" Width="100" Margin="10" HorizontalAlignment="Right"
                Command="{Binding Cmd}" CommandParameter="Save"/>
        <Grid Grid.Column="1" DataContext="{Binding ElementName=datagrid, Path=SelectedItem}"
              Margin="0,0,0,50">
          <DataGrid ItemsSource="{Binding Prices}" AutoGenerateColumns="False" Margin="10">
            <DataGrid.Columns>
              <DataGridTextColumn Header="FromQuantity" Binding="{Binding FromQuantity}"/>
              <DataGridTextColumn Header="Price" Binding="{Binding Price}"/>
              <DataGridTextColumn Header="ServiceFee" Binding="{Binding ServiceFee}"/>
            </DataGrid.Columns>
          </DataGrid>
        </Grid>
      </Grid>
    </Window>
    

    and code:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace WpfApp043
    {
    	class ProductPriceViewModel : INotifyPropertyChanged
    	{
    		// ctor
    		public ProductPriceViewModel() => ProductPriceList = new ObservableCollection<Products>();
    
    		// Path of xml file
    		public string FilePath { get; set; } = @"Window041XML.txt";
    
    		// View member
    		private CollectionViewSource cvs = new CollectionViewSource();
    		public ICollectionView View { get => cvs.View; }
    
    		private ObservableCollection<Products> _productPriceList;
    		private ObservableCollection<Products> ProductPriceList
    		{
    			get => this._productPriceList;
    			set
    			{
    				this._productPriceList = value;
    				cvs.Source = value;
    				OnPropertyChanged(nameof(View));
    			}
    		}
    
    		private bool _isSelected;
    		public bool IsSelected
    		{
    			get { return _isSelected; }
    			set
    			{
    				this._isSelected = value;
    				foreach (Products prod in dataGrid.SelectedItems) prod.Visible = value.ToString();
    			}
    		}
    
    		private DataGrid dataGrid;
    
    		#region attached property
    		public static readonly DependencyProperty AttPropProperty =
    				DependencyProperty.RegisterAttached("AttProp", typeof(bool), typeof(ProductPriceViewModel), new PropertyMetadata(false, OnPropChanged));
    		public static bool GetAttProp(DependencyObject obj) => (bool)obj.GetValue(AttPropProperty);
    		public static void SetAttProp(DependencyObject obj, bool par) => obj.SetValue(AttPropProperty, par);
    		private static void OnPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    		{
    			DataGrid dg = d as DataGrid;
    			if (dg == null) return;
    			((ProductPriceViewModel)(dg.DataContext)).dataGrid = dg;
    		}
    		#endregion
    
    		public ObservableCollection<Products> SelectedItems { get; } = new ObservableCollection<Products>();
    
    		// Commands
    		public ICommand Cmd { get => new RelayCommand(executemethod, canexecutemethod); }
    
    		private void executemethod(object obj)
    		{
    			switch (obj.ToString())
    			{
    				case "Save":
    					SaveProductsPriceList();
    					break;
    				case "Clear":
    					ProductPriceList.Clear();
    					break;
    				case "Load":
    					ProductPriceList = GetProductsPriceList();
    					break;
    				default:
    					break;
    			}
    		}
    		private static bool canexecutemethod(object obj) => true;
    
    		private XmlDocument productDoc;
    
    #pragma warning disable CS8601 // Dereference of a possibly null reference.
    #pragma warning disable CS8602 // Dereference of a possibly null reference.
    		private ObservableCollection<Products> GetProductsPriceList() //to read xml file contents 
    		{
    			var products = new ObservableCollection<Products>();
    			productDoc = new XmlDocument();
    			productDoc.Load(FilePath);
    			XElement xe0 = XElement.Parse(productDoc.InnerXml);
    			foreach (var xe1 in xe0.Descendants("Products").Elements())
    			{
    				var p = new Products
    				{
    					SysId = xe1.Attribute("Sys_Oid")?.Value,
    					Mainproduct = xe1.Name.ToString(),
    					Name = xe1.Attribute("Name")?.Value,
    					Visible = xe1.Descendants("ProductVisibility")?.FirstOrDefault().Attribute("Visible")?.Value,
    				};
    				foreach (XElement xe2 in xe1.Descendants("ProductPrice"))
    				{
    					p.Prices.Add(new PriceDetail()
    					{
    						Sys_Oid = xe2.Attribute("Sys_Oid")?.Value,
    						Price = xe2.Attribute("Price")?.Value,
    						FromQuantity = xe2.Attribute("FromQuantity")?.Value,
    						ServiceFee = xe2.Attribute("ServiceFee").Value
    					});
    				}
    				products.Add(p);
    			}
    			return products;
    		}
    
    		private void SaveProductsPriceList() //to save xml fiel contents 
    		{
    			foreach (XmlElement pn in productDoc.SelectNodes("/Data/Products/*"))
    			{
    				Products pp = ProductPriceList.Where(p => p.SysId == pn.GetAttribute("Sys_Oid")?.ToString()).FirstOrDefault();
    				if (pp != null)
    				{
    					foreach (XmlNode visibility in pn.SelectNodes("Visibilities"))
    					{
    						foreach (XmlNode productVisibilty in visibility.SelectNodes("ProductVisibility"))
    						{
    							productVisibilty.Attributes["Visible"].InnerText = pp.Visible;
    							foreach (XmlNode price in productVisibilty.SelectNodes("Prices"))
    							{
    								foreach (XmlNode productPrice in price.SelectNodes("ProductPrice"))
    								{
    									PriceDetail pd = pp.Prices.Where(p => p.Sys_Oid == productPrice.Attributes["Sys_Oid"]?.Value.ToString()).FirstOrDefault();
    									if (pd != null)
    									{
    										productPrice.Attributes["FromQuantity"].InnerText = pd.FromQuantity;
    										productPrice.Attributes["Price"].InnerText = pd.Price;
    										productPrice.Attributes["ServiceFee"].InnerText = pd.ServiceFee;
    									}
    								}
    							}
    
    						}
    					}
    				}
    			}
    			productDoc.Save(FilePath);
    		}
    
    		public static string RenameToCentiMeters(string inches)
    		{
    			var dic = GetInchesToCentimetersPairs();
    			foreach (var pair in dic.OrderByDescending(x => x.Key.Length))
    				inches = inches.Replace(pair.Key, pair.Value);
    			return inches;
    		}
    
    		private static Dictionary<string, string> GetInchesToCentimetersPairs()
    		{
    			var dic = new Dictionary<string, string>();
    			dic.Add("2x4", "5x10");
    			dic.Add("2x4/8", "5x10/20");
    			return dic;
    		}
    
    		// INotifyPropertyChanged
    #pragma warning disable CS8612 // Nullability of reference types in type doesn't match implicitly implemented member.
    		public event PropertyChangedEventHandler PropertyChanged;
    		public void OnPropertyChanged([CallerMemberName] string info = "") =>
    				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
    	}
    
    	//#pragma warning disable CS8603 // Dereference of a possibly null reference.
    	public class Products : INotifyPropertyChanged
    	{
    		public string SysId { get; set; }
    		public string Mainproduct { get; set; }
    		public string Name { get; set; }
    
    		private string _visible;
    		public string Visible
    		{
    			get => this._visible;
    			set
    			{
    				this._visible = value;
    				OnPropertyChanged();
    			}
    		}
    		public PriceDetail PriceDetail { get; set; }
    		public List<PriceDetail> Prices { get; set; } = new List<PriceDetail>();
    
    		// INotifyPropertyChanged
    #pragma warning disable CS8612 // Nullability of reference types in type doesn't match implicitly implemented member.
    		public event PropertyChangedEventHandler PropertyChanged;
    		public void OnPropertyChanged([CallerMemberName] string info = "") =>
    				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
    	}
    
    	public class PriceDetail
    	{
    		public string Sys_Oid { get; set; }
    		public string FromQuantity { get; set; }
    		public string Price { get; set; }
    		public string ServiceFee { get; set; }
    	}
    
    #pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes).
    #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
    	public class RelayCommand : ICommand
    	{
    		private readonly Predicate<object> _canExecute;
    		private readonly Action<object> _action;
    		public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
    		public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
    		public void Execute(object o) => _action(o);
    		public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
    		public event EventHandler CanExecuteChanged
    		{
    			add { CommandManager.RequerySuggested += value; }
    			remove { CommandManager.RequerySuggested -= value; }
    		}
    	}
    }
    

    Result:

    x


1 additional answer

Sort by: Most helpful
  1. Hui Liu-MSFT 48,676 Reputation points Microsoft External Staff
    2023-02-24T09:49:36.5633333+00:00

    For using CheckBox to select all DataGridRow, you could try the following code.

    
     <Window.DataContext >
            <local:ViewMode />
        </Window.DataContext>
        <StackPanel>
            <CheckBox Width="120" Name="cselectall" Content="Select All" Grid.Column="1" VerticalAlignment="Bottom" Margin="30,0,0,30"
    	IsChecked="{Binding IsSelected,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right"/>
            <DataGrid Name="dg" ItemsSource="{Binding Persons}" AutoGenerateColumns="False" CanUserAddRows="False"  >
    <DataGrid.Columns>
        <DataGridTextColumn Header="ID" Binding="{Binding ID}"  />
        <DataGridTextColumn x:Name="Name1" Header="Name" Binding="{Binding Name}"/>
    
    
    
       
        <DataGridTemplateColumn x:Name="Check" >
            <DataGridTemplateColumn.Header >
                <TextBlock Text="Visible" x:Name="headerCheckBox"   />
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate >
                <DataTemplate>
    
                   
                    <CheckBox x:Name="CheckSelected" Background="Orange" IsChecked="{Binding IsChecked,ElementName=cselectall,Mode=OneWay}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
    
    </DataGrid>
    
    
     public class ViewMode : INotifyPropertyChanged
    {
    public ObservableCollection<Person> Persons { get; set; }
    public ViewMode()
    {
    Persons = new ObservableCollection<Person>();
    Persons.Add(new Person { ID = 1, Name = "man", Visible = "true" });
    Persons.Add(new Person { ID = 2, Name = "john", Visible = "false" });
    Persons.Add(new Person { ID = 3, Name = "jo", Visible = "false" });
    }
    protected void OnPropertyChanged(string porpName)
    {
    var temp = PropertyChanged;
    if (temp != null)
        temp(this, new PropertyChangedEventArgs(porpName));
    
    }
    public event PropertyChangedEventHandler PropertyChanged;
    }
    public class Person
    {
    public int ID { get; set; }
    public string Name { get; set; }
    public string Visible { get; set; }
    }
    

    The result:

    123

    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.