WPF 4: Using DataGrid Context-Menu for Performing Insertion and Deletion Operations

In most cases, when you develop WPF UI application with the DataGrid control, end-users demand Excel like features with various shortcuts for performing Insert and Delete operations. The WPF DataGrid Context Menu helps us to develop similar kind of UI applications. In the code snippet given below, I have explained the same.

Note: You may also want to read WPF 4 DataGrid: Delete Multiple Rows

Step 1: Open VS2010 and create a WPF application, name it as
‘WPF4.0_DataGrid_Rows_Management’. In this project add the class file with following classes:

    /// <summary>
    /// The Entity Class
    /// </summary>
    public class Employee
    {
        public int EmpNo { get; set; }
        public string EmpName { get; set; }
        public int Salary { get; set; }
        public string Designation { get; set; }
    }

    /// <summary>
    /// The Model Class
    /// </summary>
    public class EmployeeCollection : ObservableCollection<Employee>
    {
        public EmployeeCollection()
        {
            Add(new Employee() { EmpNo = 101, EmpName = "Yudhistir",
                Designation = "KING", Salary = 2000000 });
            Add(new Employee() { EmpNo = 102, EmpName = "Bheem",
                Designation = "KOSHDHIKARI", Salary = 1500000 });
            Add(new Employee() { EmpNo = 103, EmpName = "Arjun",
                Designation = "SUPREME COMMANDOR", Salary = 1200000 });
            Add(new Employee() { EmpNo = 104, EmpName = "Sahdev",
                Designation = "CHIEF COMMANDOR", Salary = 1000000 });
            Add(new Employee() { EmpNo = 105, EmpName = "Nakul",
                Designation = "CHIEF MEDICAL OFFICER", Salary = 1000000 });
            Add(new Employee() { EmpNo = 106, EmpName = "Krishna",
                Designation = "CHIEF STRATEGY ADVISOR", Salary = 8000000 });
            Add(new Employee() { EmpNo = 107, EmpName = "Dustdyumna",
                Designation = "MILITARY CHIEF", Salary = 1000000 });
            Add(new Employee() { EmpNo = 108, EmpName = "Abhmanyu",
                Designation = "Lt. GENERAL", Salary = 1000000 });
        }
    }


The above classes define Entity and Collection class for Employee.

Step 2: In the same project, add a new class for performing the DML operations as below:

/// <summary>
    /// The Class is used for Data Manipulation
    /// </summary>
    public class DataOperations
    {
        EmployeeCollection Employees;
        public DataOperations()
        {
            Employees = new EmployeeCollection();
        }

        public EmployeeCollection InsertRecord(int Index)
        {
            Employees.Insert(Index+1, new Employee());
            return Employees;
        }

        public EmployeeCollection DeleteRecord(int Index)
        {
            Employees.RemoveAt(Index);
            return Employees;
        }
}


The above class performs Insert and Delete operation on the Employee collection.

Step 3: In the same project, add a Command and ViewModel class. The command class defines command for Performing Insert and Delete command. The command class implements ICommand interface. This command object is bound with the UI for performing operation. The ViewModel class define properties used for DataBinding with UI. The code is as below:

public class ViewModel : INotifyPropertyChanged
    {
        RelayCommand _InsertCommand, _DeleteCommand;

        public RelayCommand DeleteCommand
        {
            get { return _DeleteCommand; }
            set { _DeleteCommand = value; }
        }

        public RelayCommand InsertCommand
        {
            get { return _InsertCommand; }
            set { _InsertCommand = value; }
        }

        DataOperations objDML;

        public ViewModel()
        {
            objDML = new DataOperations();
            InsertCommand = new RelayCommand(Res =>
        Employees= objDML.InsertRecord(RecordIndex));
            DeleteCommand = new RelayCommand(Res =>
        Employees = objDML.DeleteRecord(RecordIndex));
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string pName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
            new PropertyChangedEventArgs(pName) );
            }   
        }

int _RecordIndex;
public int RecordIndex
{
    get { return _RecordIndex; }
    set
    {
        _RecordIndex = value;
        OnPropertyChanged("RecordIndex");
    }
}

    EmployeeCollection _Employees = new EmployeeCollection();
    public EmployeeCollection Employees
    {
        get { return _Employees; }
        set
        {
            _Employees = value;
            OnPropertyChanged("Employees");
        }
    }
}

    /// <summary>
    /// The Command Class
    /// </summary>
    public class RelayCommand : ICommand
    {
        public Action<object> actionToExecute;

        public RelayCommand(Action<object> action)
        {
            actionToExecute = action;
        }
        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {
            actionToExecute(parameter);
    }
    }


Step 4: Open the MainWindow.Xaml and write the following XAML code with DataBinding:

<Window x:Class="WPF4._0_DataGrid_Rows_Management.MainWindow"
        xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation”
        xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml”
        Title="MainWindow" Height="350" Width="742"
         xmlns:data="clr-namespace:WPF4._0_DataGrid_Rows_Management">
    <Window.Resources>
        <data:ViewModel x:Key="EmpVM"></data:ViewModel>
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource EmpVM}}">
        <DataGrid AutoGenerateColumns="False" Height="287"
                  HorizontalAlignment="Left" Margin="23,12,0,0"
                  Name="dgEmp" VerticalAlignment="Top" Width="657"
                   ItemsSource="{Binding Path=Employees}" ColumnWidth="*"
                  SelectedIndex="{Binding Path=RecordIndex,Mode=TwoWay}">
            <DataGrid.Columns>
                <DataGridTextColumn  Header="EmpNo" Binding="{Binding EmpNo}" />
                <DataGridTextColumn  Header="EmpName" Binding="{Binding EmpName}" />
                <DataGridTextColumn  Header="Salary" Binding="{Binding Salary}" />
                <DataGridTextColumn  Header="Designation" Binding="{Binding Designation}" />
            </DataGrid.Columns>
            <DataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem Command="{Binding InsertCommand}" 
            CommandParameter="{Binding RecordIndex}" Header="Insert"/>
                    <MenuItem Command="{Binding DeleteCommand}"
            CommandParameter="{Binding RecordIndex}"  Header="Delete"/>
                </ContextMenu>
            </DataGrid.ContextMenu>
        </DataGrid>
    </Grid>
</Window>


The above XAML code defines the Context Menu for Insert and Delete operation. It contains Menu-Item for Insert and Delete. InsertCommand and DeleteCommand are bind with the Command property of the Menu-Item. Since for Insert and Delete operations the Index for the record to be deleted and insert position is required the CommandParameter is bind with the RecordIndex property declared in the ViewModel class.

Step 5: Run the application and right-click on the DataGrid row. You will get a context menu  as shown below:

clip_image002
After selecting the ‘Insert’ menu the result will be as below:

clip_image004

A new row is added.

Select any row to be deleted by right clicking on the DataGrid row. The result will be as below: For e.g. I am selecting Record 104 to be deleted

clip_image006




About The Author

Mahesh Sabnis is a Microsoft MVP having over 18 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). He also blogs regularly at DotNetCurry.com. Follow him on twitter @maheshdotnet

3 comments:

Vivek said...

Hi,

Can you please show how to pass
EmpNo and EmpName as Command Bindings
in the above example?

Unknown said...

Best Implementation Of WPF Extended DataGrid Can be found here
WPF Extended DataGrid
Features
Column Choosers.
AutoFilter Control.
Export To Excel Feature.
Copy Paste To Excel and Copy Paste From Excel To DataGrid.
Three State Sorting.
Displaying Sort Order If Multiple Sort is done.
Export To Excel with formatting.
Export To PDF with formatting.

t0meck said...

Hello. I'm still learning about WPF and XAML and this whole binding stuff sometimes is hard for me to achieve.
Anyway. What I don't understand is those lines:

InsertCommand = new RelayCommand(Res => Employees = objDML.InsertRecord(RecordIndex));

DeleteCommand = new RelayCommand(Res => Employees = objDML.DeleteRecord(RecordIndex));

My question is: What's Res?
Because in my understanding it is null since it isn't declared anywhere. And since it is null then why even use this or how to use RelayCommand without passing null value