Tubc
Tubc

Reputation: 416

Create custom edit row in DataGrid wpf

By default, double clicking on a cell turns it into edit mode and when it loses focus it will commit the data or roll back if we press ESC.

I want to create a custom button to switch all cells in a row to edit mode, a button to commit changes and a button to cancel the changes.

Is this feature already supported by the Datagrid or do I have to implement all the logic myself?

I have found a way to switch all cells of a row into edit mode, but every time the textbox loses focus, it turns off edit mode

How can I prevent this? and how can I make the OK button to commit all the data?

Upvotes: 3

Views: 8791

Answers (1)

AnjumSKhan
AnjumSKhan

Reputation: 9827

Use DataGrid.BeginEdit()/CancelEdit()/CommitEdit() methods.

There are some events to handle regarding editing : BeginningEdit, CellEditEnding, PreparingCellForEdit.

Use DataGridCell.IsEditing property to turn on/off edit mode.

You can get DataGridRow, from which you can loop through it's DataGridCells. There are plenty of tutorials for this.

Exact approach for your specific needs : 1. Create 2 templates for all columns.

  1. And change the CellTemplate with CellEditingTemplate for editable column.

  2. And again change CellTemplate with old CellTemplate after Cancel/Commit.

    <DataGrid x:Name="DGrid" SelectionUnit="FullRow" AutoGenerateColumns="False" ItemsSource="{Binding Students}" Height="400" CanUserAddRows="False" Margin="10,10,405,18">
    
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <StackPanel Width="100">
                        <Button Content="Edit" Click="Button_Click_1"/>
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Width="100">
                        <Button Content="Cancel" Click="Button_Click_2"/>
                        <Button Content="Commit" Click="Button_Click_3"/>
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <TextBox Background="Aquamarine" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=Explicit}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    
    </DataGrid.Columns>
    

CodeBehind

        // Edit
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            DataGridRow row = (DataGridRow)DGrid.ItemContainerGenerator.ContainerFromItem(DGrid.CurrentItem);
            _showCellsEditingTemplate(row);
        }

        // Cancel
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            DataGridRow row = (DataGridRow)DGrid.ItemContainerGenerator.ContainerFromItem(DGrid.CurrentItem);
            _showCellsNormalTemplate(row);
        }

        // Commit
        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            DataGridRow row = (DataGridRow)DGrid.ItemContainerGenerator.ContainerFromItem(DGrid.CurrentItem);
            _showCellsNormalTemplate(row, true);
        }

        private void _showCellsEditingTemplate(DataGridRow row)
        {
            foreach (DataGridColumn col in DGrid.Columns)
            {
                DependencyObject parent = VisualTreeHelper.GetParent(col.GetCellContent(row));
                while (parent.GetType().Name != "DataGridCell")
                    parent = VisualTreeHelper.GetParent(parent);

                DataGridCell cell = ((DataGridCell)parent);
                DataGridTemplateColumn c = (DataGridTemplateColumn)col;
                if(c.CellEditingTemplate !=null)
                    cell.Content = ((DataGridTemplateColumn)col).CellEditingTemplate.LoadContent();
            }
        }

        private void _showCellsNormalTemplate(DataGridRow row, bool canCommit = false)
        {
            foreach (DataGridColumn col in DGrid.Columns)
            {
                DependencyObject parent = VisualTreeHelper.GetParent(col.GetCellContent(row));
                while (parent.GetType().Name != "DataGridCell")
                    parent = VisualTreeHelper.GetParent(parent);

                DataGridCell cell = ((DataGridCell)parent);
                DataGridTemplateColumn c = (DataGridTemplateColumn)col;
                if (col.DisplayIndex != 0)
                {
                    if (canCommit == true)
                        ((TextBox)cell.Content).GetBindingExpression(TextBox.TextProperty).UpdateSource();
                    else
                        ((TextBox)cell.Content).GetBindingExpression(TextBox.TextProperty).UpdateTarget();
                }
                cell.Content = c.CellTemplate.LoadContent();                
            }
        }     



public class ViewModel
    {
        ObservableCollection<Student> _students = new ObservableCollection<Student>();
        public ObservableCollection<Student> Students
        { get { return _students; } set { _students = value; } }

        public ViewModel()
        {
            Students.Add(new Student() { Name = "Prashant", Address = "123, N2 B, Barkheda" });
            Students.Add(new Student() { Name = "Amit", Address = "123, N2 B, Piplani" });
            Students.Add(new Student() { Name = "Gopi", Address = "Subhash Nagar" });
            Students.Add(new Student() { Name = "S. Sachin", Address = "HabibGanj" });
        }
    }

    public class Student
    {
        public string Name { get; set; }
        public string Address { get; set; }
    }

Upvotes: 6

Related Questions