WPF Select All Checkbox in a DataGrid DataBinding (Using Xampp, SQLYog, ODBC Driver)

Superbia15 20 Reputation points
2024-04-30T06:36:42.5033333+00:00

Hi! Everyone

I have been searching and integrating all checkbox multiselect from the answers I found online, and I l learnt so much, whether they use MVVM Light tollkit and Non-MVVM approach. All of them runs in different way but all are fulfilled the select all requirement that I needed.

The issue I am encountering raises when I use to integrate my DataGrid Loader (LoadDGV) after doing it in Hardcore data

Here are my snippets for select all that runs correctly

using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;


namespace chkSelectAll
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private List<Item> _items;

        public List<Item> Items
        {
            get { return _items; }
            set
            {
                _items = value;
                OnPropertyChanged();
            }
        }

        private bool? isAllSelected;

        public bool? IsAllSelected
        {
            get { return isAllSelected; }
            set
            {
                //Console.WriteLine($"Item IsChecked set to: {value}");
                isAllSelected = value;
                OnPropertyChanged();
            }
        }

        public RelayCommand chkSelectAll { get; private set; }
        public RelayCommand chkSelectCell { get; private set; }

        public MainWindowViewModel() 
        {
            chkSelectAll = new RelayCommand(() => chkSelectAllCommand());
            chkSelectCell = new RelayCommand(() => chkSelectCellCommand());

            Items = GetItems();

            IsAllSelected = false;
        }

        private void chkSelectAllCommand()
        {
            if (IsAllSelected == true)
                Items.ForEach(x => x.IsChecked = true);
            else
                Items.ForEach(x => x.IsChecked = false);
        }

        private void chkSelectCellCommand()
        {
            bool anyUnchecked = Items.Any(x => x.IsChecked == false);

            if (Items.All(x => x.IsChecked))
                IsAllSelected = true;
            else if (Items.All(x => !x.IsChecked))
                IsAllSelected = false;
            else if (Items.Any(x => x.IsChecked == anyUnchecked))
                IsAllSelected = null;
        }

        private List<Item> GetItems()
        {
            return new List<Item>
            {
                new Item { ItemID = 1, ItemName = "Lettuce", ItemCode = "1001", ItemGroup = "Group 1", LastPurchaseDate = "2024-04-21", OnHand = "15.00" },
                new Item { ItemID = 6, ItemName = "Chicken", ItemCode = "1006", ItemGroup = "Group 2", LastPurchaseDate = "2024-04-23", OnHand = "40.00" },
                new Item { ItemID = 9, ItemName = "Shrimp", ItemCode = "1009", ItemGroup = "Group 3", LastPurchaseDate = "2024-04-23", OnHand = "55.00" }
            };
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class Item : INotifyPropertyChanged
    {
        private bool _isChecked;
        public bool IsChecked
        {
            get { return _isChecked; }
            set
            {
                _isChecked = value;
                OnPropertyChanged();
            }
        }

        public int ItemID { get; set; }
        public string ItemName { get; set; }
        public string ItemCode { get; set; }
        public string ItemGroup { get; set; }
        public string LastPurchaseDate { get; set; }
        public string OnHand { get; set; }


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Here's MainWindow.xaml:

    <ResourceDictionary>
      <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:chkSelectAll.ViewModel" />
    </ResourceDictionary>

<Window x:Class="chkSelectAll.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:chkSelectAll"
        mc:Ignorable="d"
        DataContext="{Binding Source={StaticResource Locator}, Path=MainWindow}"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <DataGrid Name="DGV" ItemsSource="{Binding Items}" AutoGenerateColumns="False" CanUserAddRows="False" SelectionChanged="DGV_SelectionChanged">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.HeaderTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding DataContext.IsAllSelected, RelativeSource={RelativeSource AncestorType=DataGrid}, Mode=TwoWay}"
                                      Command="{Binding DataContext.chkSelectAll, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.HeaderTemplate>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                      Command="{Binding DataContext.chkSelectCell, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="Item Name" Binding="{Binding Path=ItemName}" IsReadOnly="True" />
                <DataGridTextColumn Header="Item Code" Binding="{Binding Path=ItemCode}" IsReadOnly="True" CanUserSort="False"/>
                <DataGridTextColumn Header="Item Group" Binding="{Binding Path=ItemGroup}" IsReadOnly="True" />
                <DataGridTextColumn Header="Last Purchase Date" Binding="{Binding Path=LastPurchaseDate}" IsReadOnly="True" />
                <DataGridTextColumn Header="On Hand" Binding="{Binding Path=OnHand}" IsReadOnly="True" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Here using HardCore Data:SelectAll HardCore Data

Here's my integration of LoadDGV inside the MainWindow:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LoadDGV(null, null);
        }
        #region LoadDGV
        public void LoadDGV(object sender, RoutedEventArgs e)
        {
            //OdbcConnection conn = null;
            OdbcCommand cmd;
            string sql = @"SELECT 
                items.ItemID,
                items.ItemName, 
                CONCAT(itemprefixes.Prefix, items.ItemCodeNumber) AS ItemCode, 
                itemgroups.GroupName AS ItemGroup,
                DATE_FORMAT(items.LastPurchaseDate, '%d %M %Y') AS LastPurchaseDate,
                CONCAT(units.UnitName, ' ', TRIM(TRAILING '.' FROM TRIM(TRAILING '0' FROM ROUND(items.OnHand, 1)))) AS OnHand
            FROM 
                items 
            INNER JOIN 
                itemgroups ON items.ItemGroupID = itemgroups.GroupID 
            INNER JOIN 
                units ON items.UnitID = units.UnitID 
            INNER JOIN 
                itemprefixes ON items.PrefixID = itemprefixes.PrefixID
            WHERE 
                items.IsActive = 1";

            OdbcDataAdapter da = new OdbcDataAdapter();
            //DataTable dt = new DataTable();
            DataSet ds = new DataSet();
            DataTable dt = new DataTable();
            try
            {
                ModConn.dbConnect();
                cmd = new OdbcCommand(sql, ModConn.conn);
                da.SelectCommand = cmd;
                da.Fill(ds, "Items");
                dt = ds.Tables["Items"];
                ds.Tables["Items"].DefaultView.Sort = "ItemID";
                ds.Tables["Items"].DefaultView.Table.Columns["ItemID"].ColumnMapping = MappingType.Hidden;
                #region Items
                List<Item> items = new List<Item>();
                foreach (DataRow row in dt.Rows)
                {
                    Item item = new Item
                    {
                        ItemID = Convert.ToInt32(row["ItemID"]),
                        ItemName = row["ItemName"].ToString(),
                        ItemCode = row["ItemCode"].ToString(),
                        ItemGroup = row["ItemGroup"].ToString(),
                        LastPurchaseDate = row["LastPurchaseDate"].ToString(),
                        OnHand = row["OnHand"].ToString()
                    };
                    items.Add(item);
                }
                #endregion
                DGV.ItemsSource = ds.Tables["Items"].DefaultView;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message, "DB Connection Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                if (ModConn.conn != null && ModConn.conn.State == ConnectionState.Open)
                {
                    ModConn.conn.Close(); // Close the connection in the finally block
                    ModConn.conn.Dispose();
                    //GC.Collect;
                }
            }
        }
        #endregion
    }

ModConn Class:

using System.Data;
using System.Configuration;
namespace CRUD_InventoryManagement
{
    public static class ModConn
    {
        public static OdbcConnection conn;
        public static void dbConnect()
        {
            try
            {
                string connectionString = ConfigurationManager.ConnectionStrings["MyDSN"].ConnectionString;
                conn = new OdbcConnection(connectionString);
                if (conn.State == ConnectionState.Closed)
                {
                    conn.Open();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);
            }
        }
    }
}

Here using Data Binding:SelectAll DataBinding

Like what I said, the problem rises when I integrate my LoadDGV to populate from the database

NOTE: I am using SQL Yog IDE and ODBC Data Source Name for database manipulation and connection

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,686 questions
{count} votes

Accepted answer
  1. Hui Liu-MSFT 41,331 Reputation points Microsoft Vendor
    2024-05-01T08:22:12+00:00

    Hi,@Superbia15. Could you change the LoadDGV method like above and add it to the MainWindowViewModel and then call it to populate the List<Item> and bind to the DataGrid? Your integration code directly sets the List<Item> to the ItemsSource instead of binding.

    
    private List<Item> GetItems()
    
    {
    
        List<Item> l = LoadDGV();
    
        return l;
    
    }
            public List<Item> LoadDGV()
    
            {
              ...
                        List<Item> items = new List<Item>();
    
                        foreach (DataRow row in dt.Rows)
    
                        {
    
                            Item item = new Item
    
                            {
    
                                ItemID = Convert.ToInt32(row["ItemID"]),
    
                                ItemName = row["ItemName"].ToString(),
    
                                ItemCode = row["ItemCode"].ToString(),
    
                                ItemGroup = row["ItemGroup"].ToString(),
    
                                LastPurchaseDate = row["LastPurchaseDate"].ToString(),
    
                                OnHand = row["OnHand"].ToString()
                            };
    
                            items.Add(item);
    
                        }
                        return items;
                    }
    
                    catch (Exception ex)
                    {
                        Console.WriteLine("Error: " + ex.Message);
    
                        return null;
                     }
    
    }
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    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.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful