How to number rows in dataGrid

vitaminchik 486 Reputation points
2023-04-21T19:46:25.7133333+00:00

Hello. I am using datagrid. Is it possible to make it possible for the user to add a combined row or with columns by clicking on the table? And how it is possible to make numbering of lines as an example? If a combined string is encountered, then the counting starts over. And how to be if the user deletes lines? How to make it so that the account does not go as tray?User's image

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,853 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,452 questions
{count} votes

Accepted answer
  1. Hui Liu-MSFT 48,666 Reputation points Microsoft External Staff
    2023-04-28T08:21:46.1433333+00:00

    Hi,@vitaminchik. For updating the row number when adding and deleting items, you could create a custom property DisplayRowNumber and use local : DataGridBehavior. DisplayRowNumber = "True" in DataGrid.

    You can refer to the code below.

     <Window.Resources>
            <local:SelectedItemToItemsSource x:Key="SelectedItemToItemsSource"/>
            <DataTemplate x:Key="UserGrid">
                <Border Background="Chocolate" BorderBrush="Black" BorderThickness="1" CornerRadius="5" >
                    <Grid Margin="10">
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="No1" Grid.Row="1" Grid.Column="0"/>
                        <TextBlock Text="No2" Grid.Row="2" Grid.Column="0"/>
                        <TextBlock Text="Name" Grid.Row="3" Grid.Column="0"/>
                        <TextBlock Text="Description" Grid.Row="4" Grid.Column="0"/>
                        <TextBlock Text="WorkersCategory" Grid.Row="5" Grid.Column="0"/>
                        <TextBlock Text="Time" Grid.Row="6" Grid.Column="0"/>
                        <TextBlock Text="PriceRate" Grid.Row="7" Grid.Column="0"/>
                        <TextBlock Text="Specifications" Grid.Row="8" Grid.Column="0"/>
                     
                        <TextBox Text="{Binding No1, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="1"/>
                        <TextBox Text="{Binding No2, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="2"/>
                        <TextBox Text="{Binding Name, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="3"/>
                        <TextBox Text="{Binding Description, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="4"/>
                        <TextBox Text="{Binding WorkersCategory, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="5"/>
                        <TextBox Text="{Binding Time, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="6"/>
                        <TextBox Text="{Binding PriceRate, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="7"/>
                        <TextBox Text="{Binding Specifications, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="8"/>
                      
                        <StackPanel Orientation="Horizontal" Grid.Row="11" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="5,5,5,5">
                            <Button Foreground="White" Background="Green" Content="Cancel" Command="{Binding DataContext.CancelCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
                            <Button Foreground="White" Background="Green" Content="Delete" Command="{Binding DataContext.DeleteUserCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
                            <Button Foreground="White" Background="Green" Content="Save" Command="{Binding DataContext.SaveCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
                            <Button Foreground="White" Background="Green" Content="Add" Command="{Binding DataContext.AddCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
                        </StackPanel>
                    </Grid>
                </Border>
            </DataTemplate>
        </Window.Resources>
        <Grid Margin="0,0,0,-1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="7*"/>
                <ColumnDefinition Width="3*"/>
            </Grid.ColumnDefinitions>
            <GroupBox Header="Data" HorizontalAlignment="Center" VerticalAlignment="Center" Height="383" Margin="5,5,5,5">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <DataGrid x:Name="dg1" ItemsSource="{Binding Infos}" SelectedItem="{Binding SelectedInfo}" CanUserAddRows="False"       local:DataGridBehavior.DisplayRowNumber="True" 
                                  CanUserDeleteRows="False" SelectionMode="Single" SelectedIndex="{Binding SelectedIndex}" VerticalAlignment="Top"   
                                  AutoGenerateColumns="False" Margin="5,5,5,5">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="No1" Binding="{Binding No1}"/>
                            <DataGridTextColumn Header="No2" Binding="{Binding No2}"/>
                            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
                            <DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
                            <DataGridTextColumn Header="WorkersCategory" Binding="{Binding WorkersCategory}"/>
                            <DataGridTextColumn Header="Time" Binding="{Binding Time}"/>
                            <DataGridTextColumn Header="PriceRate" Binding="{Binding PriceRate}"/>
                            <DataGridTextColumn Header="Specifications" Binding="{Binding Specifications}"/>
                        </DataGrid.Columns>
                    </DataGrid>
                </Grid>
            </GroupBox>
            <ItemsControl BindingGroup="{Binding UpdateBindingGroup, Mode=OneWay}"  VerticalAlignment="Top" Margin="5,5,5,5" Grid.Column="1"  
                          ItemTemplate="{StaticResource UserGrid}"  ItemsSource="{Binding SelectedInfo, Converter={StaticResource SelectedItemToItemsSource}}"    />
    
        </Grid>
    
    

    Codebedhind:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SQLite;
    using System.Globalization;
    using System.Windows;
    using System.Windows.Controls.Primitives;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Threading;
    using System.Xml.Linq;
    
    namespace CURDdemo
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
    
                InitializeComponent();
                DatabaseLayer.LoadData();
                this.DataContext = new ViewModelUser();
            }
        }
        public class ViewModelUser : ViewModelBase
        {
    
            public ViewModelUser()
            {
                personnel = new PersonnelBusinessObject();
                personnel.InfoChanged += new EventHandler(personnel_InfoChanged);
                UpdateBindingGroup = new BindingGroup { Name = "Group1" };
                CancelCommand = new RelayCommand(DoCancel);
                SaveCommand = new RelayCommand(DoSave);
                AddCommand = new RelayCommand(AddUser);
                DeleteUserCommand = new RelayCommand(DeleteUser);
            }
            PersonnelBusinessObject personnel;
    
            private ObservableCollection<Info> _Info;
            public ObservableCollection<Info> Infos
            {
                get
                {
                    _Info = new ObservableCollection<Info>(personnel.GetInfos());
                    return _Info;
                }
            }
            public int SelectedIndex { get; set; }
            object _SelectedInfo;
            public object SelectedInfo
            {
                get
                {
                    return _SelectedInfo;
                }
                set
                {
                    if (_SelectedInfo != value)
                    {
                        _SelectedInfo = value;
                        OnPropertyChanged("SelectedInfo");
                    }
                }
            }
            private BindingGroup _UpdateBindingGroup;
            public BindingGroup UpdateBindingGroup
            {
                get
                {
                    return _UpdateBindingGroup;
                }
                set
                {
                    if (_UpdateBindingGroup != value)
                    {
                        _UpdateBindingGroup = value;
                        OnPropertyChanged("UpdateBindingGroup");
                    }
                }
            }
            void personnel_InfoChanged(object sender, EventArgs e)
            {
                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
                {
                    OnPropertyChanged("Infos");
                }));
            }
            public RelayCommand CancelCommand { get; set; }
            public RelayCommand SaveCommand { get; set; }
            public RelayCommand AddCommand { get; set; }
            public RelayCommand DeleteUserCommand { get; set; }
    
            void DoCancel(object param)
            {
                UpdateBindingGroup.CancelEdit();
                if (SelectedIndex == -1)    //This only closes if new - just to show you how CancelEdit returns old values to bindings  
                    SelectedInfo = null;
            }
    
            void DoSave(object param)
            {
                UpdateBindingGroup.CommitEdit();
                var info = SelectedInfo as Info;
                if (SelectedIndex == -1)
                {
                    personnel.AddInfo(info);
                    OnPropertyChanged("Employee"); // Update the list from the data source  
                }
                else
                    personnel.UpdateInfo(info);
    
                SelectedInfo = null;
            }
    
            void AddUser(object param)
            {
                SelectedInfo = null; // Unselects last selection. Essential, as assignment below won't clear other control's SelectedItems  
                var info = new Info();
                SelectedInfo = info;
            }
    
            void DeleteUser(object parameter)
            {
                var info = SelectedInfo as Info;
                if (SelectedIndex != -1)
                {
                    personnel.DeleteInfo(info);
                    OnPropertyChanged("Employee"); // Update the list from the data source  
                }
                else
                    SelectedInfo = null; // Simply discard the new object  
            }
        }
    
        public static class DatabaseLayer
        {
            public static void LoadData()
            {
                SQLiteConnection.CreateFile("MyDatabase.sqlite");
                SQLiteConnection m_dbConnection = new SQLiteConnection("Data Source=MyDatabase.sqlite");
                m_dbConnection.Open();
    
    
                string sql = "create table MyData (Id INTEGER PRIMARY KEY AUTOINCREMENT, No1 varchar(20), No2 varchar(20), Name varchar(20) ,Description varchar(20) ," +
                    "WorkersCategory varchar(20),Time  varchar(20),PriceRate  varchar(20),Specifications  varchar(20)) ";
                SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
                command.ExecuteNonQuery();
    
                sql = "INSERT INTO MyData(No1,No2, Name,Description,WorkersCategory,Time,PriceRate,Specifications) VALUES('NO1 ', 'NO2','NAME1','D1','TEXT','TEXT','TEXT','TEXT')";
                command = new SQLiteCommand(sql, m_dbConnection);
                command.ExecuteNonQuery();
    
                sql = "INSERT INTO MyData(No1,No2, Name,Description,WorkersCategory,Time,PriceRate,Specifications)  VALUES('NO1 ', 'NO2','NAME2','D2','TEXT','TEXT','TEXT','TEXT')";
                command = new SQLiteCommand(sql, m_dbConnection);
                command.ExecuteNonQuery();
    
                m_dbConnection.Close();
            }
            public static List<Info> GetInfoFromDatabase()
            {
                try
                {
                    SQLiteConnection m_dbConnection = new SQLiteConnection("Data Source=MyDatabase.sqlite");
                    SQLiteCommand sqlCom = new SQLiteCommand("Select * From MyData", m_dbConnection);
                    SQLiteDataAdapter sda = new SQLiteDataAdapter(sqlCom);
                    DataTable dt = new DataTable();
                    sda.Fill(dt);
                    var Employee = new List<Info>();
                    foreach (DataRow row in dt.Rows)
                    {
                        var obj = new Info()
                        {
                            Id = Convert.ToInt32(row["Id"]),
                            No1 = (string)row["No1"],
                            No2 = (string)row["No2"],
                            Name = (string)(row["Name"]),
                            Description = (string)row["Description"],
                          
                            WorkersCategory = (string)(row["WorkersCategory"]),
                            Time = (string)(row["Time"]),
                            PriceRate = (string)(row["PriceRate"]),
                            Specifications = (string)(row["Specifications"]),
                           // Equipment = (ObservableCollection<Equi>)row["Equipment"],
                        };
                        Employee.Add(obj);
                        m_dbConnection.Close();
                    }
                    return Employee;
    
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
           
            internal static int InsertInfo(Info info)
            {
                try
                {
                    const string query = "INSERT INTO MyData(No1,No2, Name,Description,WorkersCategory,Time,PriceRate,Specifications) VALUES(@No1, @No2,@Name,@Description,@WorkersCategory,@Time,@PriceRate,@Specifications)";
                    var args = new Dictionary<string, object>
         {
               {"@No1", info.No1},
               {"@No2", info.No2},
               {"@Name", info.Name},
               {"@Description", info.Description},
               {"@WorkersCategory", info.WorkersCategory},
               {"@Time", info.Time},
               {"@PriceRate", info.PriceRate},
               {"@Specifications", info.Specifications},
               
         };
                    return ExecuteWrite(query, args);
                    MessageBox.Show("Data Saved Successfully.");
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
    
                }
            }
    
            internal static int UpdateInfo(Info info)
            {
                try
                {
                    const string query = "UPDATE MyData SET No1 = @No1, No2 = @No2, Name=@Name, Description=@Description, WorkersCategory=@WorkersCategory , WorkersCategory=@WorkersCategory,Time=@Time,PriceRate=@PriceRate,Specifications=@SpecificationsWHERE Id = @Id";
    
                    var args = new Dictionary<string, object>
        {
             {"@Id", info.Id},
             {"@No1", info.No1},
               {"@No2", info.No2},
               {"@Name", info.Name},
               {"@Description", info.Description},
               {"@WorkersCategory", info.WorkersCategory},
               {"@Time", info.Time},
               {"@PriceRate", info.PriceRate},
               {"@Specifications", info.Specifications},
              
        };
    
                    return ExecuteWrite(query, args);
                    MessageBox.Show("Data Updated Successfully.");
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
    
                }
            }
    
            internal static int DeleteInfo(Info info)
            {
                try
                {
                    const string query = "Delete from MyData WHERE Id = @id";
                    var args = new Dictionary<string, object>
            {
              {"@id", info.Id}
            };
                    return ExecuteWrite(query, args);
                    MessageBox.Show("Data Deleted Successfully.");
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
    
                }
            }
            private static int ExecuteWrite(string query, Dictionary<string, object> args)
            {
                int numberOfRowsAffected;
    
                using (var con = new SQLiteConnection("Data Source=MyDatabase.sqlite"))
                {
                    con.Open();
                    using (var cmd = new SQLiteCommand(query, con))
                    {
                        foreach (var pair in args)
                        {
                            cmd.Parameters.AddWithValue(pair.Key, pair.Value);
                        }
                        numberOfRowsAffected = cmd.ExecuteNonQuery();
                    }
                    return numberOfRowsAffected;
                }
            }
        }
    
    
        public class PersonnelBusinessObject
        {
            internal EventHandler InfoChanged;
    
            List<Info> Info { get; set; }
          
            public PersonnelBusinessObject()
            {
                Info = DatabaseLayer.GetInfoFromDatabase();
           
            }
    
            public List<Info> GetInfos()
            {
                return Info = DatabaseLayer.GetInfoFromDatabase();
            }
        
            public void AddInfo(Info info)
            {
                DatabaseLayer.InsertInfo(info);
                OnInfoChanged();
            }
    
            public void UpdateInfo(Info info)
            {
                DatabaseLayer.UpdateInfo(info);
                OnInfoChanged();
            }
    
            public void DeleteInfo(Info info)
            {
                DatabaseLayer.DeleteInfo(info);
                OnInfoChanged();
            }
    
            void OnInfoChanged()
            {
                if (InfoChanged != null)
                    InfoChanged(this, null);
            }
        }
     
        public class Info : ViewModelBase
        {
            private int id;
            private string no1;
            private string no2;
            private string name;
            private string description;
           // private ObservableCollection<Equi> equipment;
            private string workersCategory;
            private string time;
            private string priceRate;
            private string specifications;
            public int Id  
            {
                get { return id; }
                set
                {
                    id = value;
                    OnPropertyChanged("Id");
                }
            }
            public string No1
            {
                get { return no1; }
                set
                {
                    no1= value;
                    OnPropertyChanged("No1");
                }
            }
            public string No2
            {
                get { return no2; }
                set
                {
                    no2 = value;
                    OnPropertyChanged("No2");
                }
            }
            public string Name
            {
                get { return name; }
                set
                {
                    name = value;
                    OnPropertyChanged("Name");
                }
            }
            public string Description
            {
                get { return description; }
                set
                {
                    description = value;
                    OnPropertyChanged("Description");
                }
            }
          
            public string WorkersCategory
            {
                get { return workersCategory; }
                set
                {
                    workersCategory = value;
                    OnPropertyChanged("WorkersCategory");
                }
            }
            public string Time
            {
                get { return time; }
                set
                {
                    time = value;
                    OnPropertyChanged("Time");
                }
            }
            public string PriceRate
            {
                get { return priceRate; }
                set
                {
                    priceRate = value;
                    OnPropertyChanged("PriceRate");
                }
            }
            public string Specifications
            {
                get { return specifications; }
                set
                {
                    specifications = value;
                    OnPropertyChanged("Specifications");
                }
            }
        }
    
        public class RelayCommand : ICommand
        {
    
            readonly Action<object> _execute;
            readonly Predicate<object> _canExecute;
    
    
            public RelayCommand(Action<object> execute)
                : this(execute, null)
            {
            }
    
            public RelayCommand(Action<object> execute, Predicate<object> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
    
                _execute = execute;
                _canExecute = canExecute;
            }
    
            public bool CanExecute(object parameter)
            {
                return _canExecute == null ? true : _canExecute(parameter);
            }
    
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
            public void Execute(object parameter)
            {
                _execute(parameter);
            }
    
        }
    
        public class SelectedItemToItemsSource : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value == null) return null;
                return new List<object>() { value };
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    
        public class ViewModelBase : INotifyPropertyChanged
        {
            internal void OnPropertyChanged(string prop)
            {
                if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
            }
            public event PropertyChangedEventHandler PropertyChanged;
        }
    
    
        public class DataGridBehavior
        {
    
            public static DependencyProperty DisplayRowNumberProperty =
                DependencyProperty.RegisterAttached("DisplayRowNumber",
                                                    typeof(bool),
                                                    typeof(DataGridBehavior),
                                                    new FrameworkPropertyMetadata(false, OnDisplayRowNumberChanged));
            public static bool GetDisplayRowNumber(DependencyObject target)
            {
                return (bool)target.GetValue(DisplayRowNumberProperty);
            }
            public static void SetDisplayRowNumber(DependencyObject target, bool value)
            {
                target.SetValue(DisplayRowNumberProperty, value);
            }
    
            private static void OnDisplayRowNumberChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
            {
                DataGrid dataGrid = target as DataGrid;
                if ((bool)e.NewValue == true)
                {
                    EventHandler<DataGridRowEventArgs> loadedRowHandler = null;
                    loadedRowHandler = (object sender, DataGridRowEventArgs ea) =>
                    {
                        if (GetDisplayRowNumber(dataGrid) == false)
                        {
                            dataGrid.LoadingRow -= loadedRowHandler;
                            return;
                        }
                        ea.Row.Header = ea.Row.GetIndex();
                    };
                    dataGrid.LoadingRow += loadedRowHandler;
    
                    ItemsChangedEventHandler itemsChangedHandler = null;
                    itemsChangedHandler = (object sender, ItemsChangedEventArgs ea) =>
                    {
                        if (GetDisplayRowNumber(dataGrid) == false)
                        {
                            dataGrid.ItemContainerGenerator.ItemsChanged -= itemsChangedHandler;
                            return;
                        }
                        GetVisualChildCollection<DataGridRow>(dataGrid).
                            ForEach(d => d.Header = d.GetIndex());
                    };
                    dataGrid.ItemContainerGenerator.ItemsChanged += itemsChangedHandler;
                }
            }
    
    
            private static List<T> GetVisualChildCollection<T>(object parent) where T : Visual
            {
                List<T> visualCollection = new List<T>();
                GetVisualChildCollection(parent as DependencyObject, visualCollection);
                return visualCollection;
            }
    
            private static void GetVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual
            {
                int count = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < count; i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(parent, i);
                    if (child is T)
                    {
                        visualCollection.Add(child as T);
                    }
                    if (child != null)
                    {
                        GetVisualChildCollection(child, visualCollection);
                    }
                }
            }
    
        }
    }
    
    

    The result:

    enter image description here

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

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


1 additional answer

Sort by: Most helpful
  1. Fei Nan 0 Reputation points
    2025-03-22T07:04:20.99+00:00

    a very useful method

    0 comments No comments

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.