Using a checkbox to select datagrid items

MrFlinstone 686 Reputation points
2020-12-03T23:55:06.927+00:00

fhfHi All.

I am developing an application which allows users to choose a list of servers, at the moment it works up to the point that the users have to hold control to select multiple rows within the datagrid.

I added a checkbox control on the datagrid to make selection easier, however I cannot get the checkbox control to effectively trigger a selection on the datagrid. Secondly for the checkbox, i am getting an extra checkbox for all the rows returned within the data grid, lets assume the datagrid returns 10 rows, I am getting 11 checkboxes.

XAML file

        <DataGrid x:Name="DGInventory"  Grid.Column="5"  SelectionChanged="datagrid_selection"  HorizontalAlignment="left"  Height="365"  Width="625" AutoGenerateColumns="False" Margin="9,159,0,0" VerticalAlignment="Top"  Grid.ColumnSpan="8" SelectedItem="{Binding PopulateDataGrid, Mode=TwoWay}"  >
            <DataGrid.Columns>
                <DataGridCheckBoxColumn  x:Name="chkSelectedServer" Binding="{Binding IsChecked}"  Header="Choose"/>
                <DataGridTextColumn  Binding="{Binding Server_Id}"  Header="Server_Id"/>
                <DataGridTextColumn  Binding="{Binding Server_Name}"  Header="Server_Name"/>
                <DataGridTextColumn  Binding="{Binding Status_Id}"  Header="Status_Id"/>
                <DataGridTextColumn  Binding="{Binding AppNo}"  Header="AppNo"/>
                <DataGridTextColumn  Binding="{Binding SQL_Instane}"  Header="SQL_Instane"/>
                <DataGridTextColumn  Binding="{Binding SQL_Instane_Port}"  Header="SQL_Instane_Port"/>
                <DataGridTextColumn  Binding="{Binding LocationName}"  Header="LocationName"/>
                <DataGridTextColumn  Binding="{Binding SoftwareVersion}"  Header="SoftwareVersion"/>

            </DataGrid.Columns>
        </DataGrid>

CS File

public void PopulateDataGrid()
{

    try
    {


        string strConnection = "Data Source=localhost\\DEV1;Initial Catalog=inventory;Integrated Security=True";

        SqlConnection con = new SqlConnection(strConnection);

        SqlCommand sqlCmd = new SqlCommand();
        sqlCmd.Connection = con;
        sqlCmd.CommandText = "EXEC sp_deployer_getserverlist ";
        SqlDataAdapter sqlDataAdap = new SqlDataAdapter(sqlCmd);
        DataTable dt = new DataTable("ServerList");
        sqlDataAdap.Fill(dt);
        DGInventory.ItemsSource = dt.DefaultView;

        int SelectedServercount = dt.DefaultView.Count;
        lblCount.Content = SelectedServercount;

        if (SelectedServercount >= 1)
        {

            btnDeploy.IsEnabled = true;
        }

    }

    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}
Developer technologies Windows Presentation Foundation
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2020-12-04T18:44:05.903+00:00

    Hi,
    try following MVVM demo:

    XAML:

    <Window x:Class="WpfApp1.Window019"  
            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:WpfApp019"  
            mc:Ignorable="d"  
            Title="Window019" Height="450" Width="800">  
      <Window.DataContext>  
        <local:ViewModel/>  
      </Window.DataContext>  
      <StackPanel>  
        <DataGrid Height="365"    
                  Width="625"   
                  AutoGenerateColumns="False"   
                  Margin="5"   
                  ItemsSource="{Binding InventorySource}"  
                  SelectedItem="{Binding PopulateDataGrid, Mode=TwoWay}">  
          <DataGrid.Columns>  
            <DataGridCheckBoxColumn Binding="{Binding IsChecked}" Header="Choose"/>  
            <DataGridTextColumn Binding="{Binding Server_Id}" Header="Server_Id"/>  
            <DataGridTextColumn Binding="{Binding Server_Name}" Header="Server_Name"/>  
            <DataGridTextColumn Binding="{Binding Status_Id}" Header="Status_Id"/>  
            <DataGridTextColumn Binding="{Binding AIT_Number}" Header="AIT_Number"/>  
            <DataGridTextColumn Binding="{Binding SQL_Long_Instance_Name}" Header="SQL_Long_Instance_Name"/>  
            <DataGridTextColumn Binding="{Binding SQL_Long_Port_Name}" Header="SQL_Long_Port_Name"/>  
            <DataGridTextColumn Binding="{Binding Region_Name}" Header="Region_Name"/>  
            <DataGridTextColumn Binding="{Binding DBA_Version}" Header="DBA_Version"/>  
          </DataGrid.Columns>  
        </DataGrid>  
        <Button Content="Deploy" Command="{Binding Cmd}" Width="100"/>  
        <Label Content="{Binding SelectedServerCount}"/>  
      </StackPanel>  
    </Window>  
    

    Code:

    using System;  
    using System.ComponentModel;  
    using System.Data;  
    using System.Data.SqlClient;  
    using System.Linq;  
    using System.Runtime.CompilerServices;  
    using System.Windows;  
    using System.Windows.Data;  
    using System.Windows.Input;  
      
    namespace WpfApp019  
    {  
      public class ViewModel : INotifyPropertyChanged  
      {  
        public ViewModel()  
        {  
          PopulateDataGrid();  
          cvs.Source = dt.DefaultView;  
          cvs.View.CurrentChanged += (sender, e) =>  
          {  
            OnPropertyChanged(nameof(SelectedServerCount));  
            OnPropertyChanged(nameof(Cmd));  
          };  
          // add IsChecked column if not exists  
          if (dt.Columns["IsChecked"] == null) dt.Columns.Add("IsChecked", typeof(bool));  
          // reset IsChecked in all rows  
          for (int i = 0; i < dt.Rows.Count; i++) dt.Rows[i]["IsChecked"] = false;  
        }  
      
        private DataTable dt = null;  
        private CollectionViewSource cvs = new CollectionViewSource();  
        public ICollectionView InventorySource { get => cvs.View; }  
        public int SelectedServerCount  
        {  
          get  
          {  
            return (from row in dt.AsEnumerable() where ((DataRow)row).Field<bool>("IsChecked") select row).Count();  
          }  
        }  
        public ICommand Cmd { get => new WpfApp1.Helper.RelayCommand(CmdExecute, CmdCanExecute); }  
        public void CmdExecute(object parameter)  
        {  
          // execute deploy  
        }  
        public bool CmdCanExecute(object parameter) => SelectedServerCount > 0;  
      
        public void PopulateDataGrid()  
        {  
          try  
          {  
            string strConnection = "Data Source=localhost\\DEV1;Initial Catalog=inventory;Integrated Security=True";  
            using (SqlConnection con = new SqlConnection(strConnection))  
            {  
              using (SqlCommand sqlCmd = new SqlCommand())  
              {  
                sqlCmd.Connection = con;  
                sqlCmd.CommandText = "EXEC sp_deployer_getserverlist ";  
                using (SqlDataAdapter sqlDataAdap = new SqlDataAdapter(sqlCmd))  
                {  
                  dt = new DataTable("ServerList");  
                  //sqlDataAdap.Fill(dt);  
                  //  
                  // for demo only  
                  FillDataTable(dt);  
                  //  
                }  
              }  
            }  
          }  
          catch (Exception ex)  
          {  
            MessageBox.Show(ex.ToString());  
          }  
        }  
      
        /// <summary>  
        /// only for demo instead of SQL database  
        /// </summary>  
        /// <param name="dt"></param>  
        private void FillDataTable(DataTable dt)  
        {  
          dt.Columns.Add("Server_Id", typeof(int));  
          dt.Columns.Add("Server_Name", typeof(string));  
          for (int i = 10; i < 30; i++) dt.Rows.Add(i, $"Server {i}");  
        }  
      
        public event PropertyChangedEventHandler PropertyChanged;  
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));  
      }  
    }  
    

    Result:

    45313-x.gif


1 additional answer

Sort by: Most helpful
  1. Timon Yang-MSFT 9,606 Reputation points
    2020-12-04T08:22:35.597+00:00

    You can add an event hander in DataGridCheckBoxColumn.ElementStyle which targets CheckBox for the DataGridCheckBoxColumn.
    The xaml code as below:

              <DataGridCheckBoxColumn  x:Name="chkSelectedServer" Binding="{Binding IsChecked}"  Header="Choose" CanUserSort="False">  
                  <DataGridCheckBoxColumn.ElementStyle>  
                      <Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}" >  
                          <EventSetter Event="Checked" Handler="OnChecked" />  
                      </Style>  
                  </DataGridCheckBoxColumn.ElementStyle>  
              </DataGridCheckBoxColumn>  
    

    cs code is:

            void OnChecked(object sender, RoutedEventArgs e)  
            {  
                var selectItems = GetSelectedItems();  
            }  
      
            public List<MyClass> GetSelectedItems()  
            {  
                var selectedItems = new List<MyClass>();  
      
                foreach (MyClass item in DGInventory.ItemsSource)  
                {  
                    if (((CheckBox)chkSelectedServer.GetCellContent(item)).IsChecked == true)  
                    {  
                        selectedItems.Add(item);  
                    }  
                }  
                return selectedItems;  
            }  
    

    The last row which shows a CheckBox lets you get or set a value that indicates whether the user can add new rows to the DataGrid, you can refer to CanUserAddRows for more details . If you don't need it,just set the CanUserAddRows=false for the DataGrid.
    Update:

        public class MyClass  
        {  
            public int ID { get; set; }  
            public string Name { get; set; }  
            public double Score { get; set; }  
            public bool IsChecked { get; set; }  
        }  
    

    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.