Issue with Date Picker needed to be used twice with Begin Edit and a Data Grid with WPF

Dyr Fenrir 21 Reputation points
2021-03-27T20:08:08.103+00:00

This is a WPF application, using a Data Grid with Date Picker.

The goal is to click on the calendar, select a date, then the Data Grid goes in edit mode so as soon as I click on another cell, the Update is done on the database and the row is added on the grid, that part is working.

But, when I initially click on the Date Picker, select the date, because I do the Data Grid Begin Edit, the date selected is never displayed in the control, it goes in Edit mode, at this point I can still click on another cell to have the Insert in the database occur and the row added to the Data Grid, but the Date is inserted as null (I can also select the date again on the Date Picker and click on another cell to have the date added to database and the added row in the Data Grid).

Is there a way to change this behavior so the Date chosen is kept and it still goes in edit mode without me having to click again on the Date Picker, select the date again and then click on another cell for the Insert to happen?

May you help me out with this please?

Here is the code for the column creation (using a Template):

        templateColumn = new DataGridTemplateColumn();  
         templateColumn.Header = "Testing date";
         FrameworkElementFactory datePickerFactoryElem = new FrameworkElementFactory(typeof(DatePicker));
         templateColumnBinding = new Binding("date_time");
         templateColumnBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
         templateColumnBinding.Mode = BindingMode.TwoWay;
         datePickerFactoryElem.AddHandler(DatePicker.SelectedDateChangedEvent, new EventHandler<SelectionChangedEventArgs>(RowEditEnding));
         datePickerFactoryElem.SetValue(DatePicker.SelectedDateProperty, templateColumnBinding);
         datePickerFactoryElem.SetValue(DatePicker.DisplayDateProperty, templateColumnBinding);
         cellTemplate.VisualTree = datePickerFactoryElem;
         templateColumn.CellTemplate = cellTemplate;

         DataGrid.Columns.Add(templateColumn);

Here is the code to begin the edit when I select a Date with the Date Picker:

    private void RowEditEnding(object sender, SelectionChangedEventArgs e)  
    {
        DataGrid.BeginEdit();
    }

Here is the code fired when I click on another cell:

    private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)  
    {
        if (!isManualEditCommit)
        {
            isManualEditCommit = true;
            DataGrid grid = (DataGrid)sender;
            grid.CommitEdit(DataGridEditingUnit.Row, true);
            isManualEditCommit = false;
        }
    }

    private void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
    {
        DataRowView rowView = e.Row.Item as DataRowView;
        rowBeingEdited_DataGrid = rowView;
    }

    private void DataGrid_CurrentCellChanged(object sender, EventArgs e)
    {
        if (rowBeingEdited_DataGrid != null)
        {
            DataGrid.CommitEdit();

            conn = new MySqlConnection(connStr);

            MySqlCommand cmdInsert;
            MySqlCommand cmdUpdate;
            cmdUpdate = new MySqlCommand(@"UPDATE…
            SET…
            WHERE…;", conn);
            cmdUpdate.Parameters.Add("…");
            cmdUpdate.Parameters.Add("…");
            cmdInsert = new MySqlCommand(@"INSERT INTO…
            (…,
            …,)
            VALUES
            …,
            …);", conn);
            cmdInsert.Parameters.Add("…");
            cmdInsert.Parameters.Add("…");

            mySqlDataAdapter.InsertCommand = cmdInsert;
            mySqlDataAdapter.UpdateCommand = cmdUpdate;

            mySqlDataAdapter.Update(dataSet);
            conn.Close();
            conn.Dispose();

            DataGrid.ItemsSource = null;
            dataSet.Reset();

            rowBeingEdited_DataGrid.EndEdit();
            rowBeingEdited_DataGrid = null;

            conn = new MySqlConnection(connStr);
            mySqlDataAdapter = new MySqlDataAdapter(@"select * from …", conn);
            command = conn.CreateCommand();
            conn.Open();

            mySqlDataAdapter.Fill(dataSet);
            DataGrid.ItemsSource = dataSet.Tables[0].DefaultView;
            conn.Close();
            conn.Dispose();
        }

     }

Thank you for your time and help, it is greatly appreciated.

Note: Variables names and controls are named better in the original code, I tried to remove as much irrelevant information so the code would be easier to read.

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,671 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.
10,245 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Karen Payne MVP 35,036 Reputation points
    2021-03-30T16:02:57.577+00:00

    With WPF, best to setup a model which implements INotifyPropertyChanged then in xaml implement UpdateSourceTrigger property and set it to either LostFocus or PropertyChanged.

    Super simple model

    using System;  
    using System.ComponentModel;  
    using System.Runtime.CompilerServices;  
      
    namespace TODO  
    {  
        public class Employee : INotifyPropertyChanged  
        {  
            private string _firstName;  
            public string FirstName  
            {  
                get => _firstName;  
                set  
                {  
                    _firstName = value;  
                    OnPropertyChanged();  
                }  
            }  
      
            private string _lastName;  
            public string LastName  
            {  
                get => _lastName;  
                set  
                {  
                    _lastName = value;  
                    OnPropertyChanged();  
                }  
            }  
      
            private DateTime _hireDateTime;  
      
            public DateTime HireDateTime  
            {  
                get => _hireDateTime;  
                set  
                {  
                    _hireDateTime = value;  
                    OnPropertyChanged();  
                }  
            }  
      
            public event PropertyChangedEventHandler PropertyChanged;  
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)  
            {  
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
            }  
        }  
    }  
      
      
    

    Resource: Data binding overview (WPF .NET)

    1 person found this answer helpful.

  2. Karen Payne MVP 35,036 Reputation points
    2021-03-31T00:22:57.95+00:00

    Correct me if I am wrong, I thought this is what the following code did:

    That is only part of what needs to be done. Note the most important thing below is the RowEditEnding event (which does an immediate save to the database) and secondly there is zero validation done while there is also a save button which does validation.

    I don't have a code sample that uses DataTable containers, did away with them 10 or so years ago but I think if you look at the following code sample which is a hodgepodge project used for teaching WPF and Entity Framework.

    82966-f1a.png

    It does not use a date control in the data grid but that does not matter what is important in is highlighted in the xaml

    83022-f1b.png

    Code behind
    Here this is Entity Framework, for a DataTable you need to implement this.

    private void EmployeeGrid_OnRowEditEnding(object sender, DataGridRowEditEndingEventArgs e)  
    {  
         
        _context.SaveChanges();  
      
    }  
    
    1 person found this answer helpful.