Введенная дата исчезает при вводе следующего поля - PullRequest
0 голосов
/ 03 августа 2020

У меня есть DatePicker, встроенный в DataGrid, привязанный к базе данных MySQL. Проблема в том, что когда пользователь вводит дату, а затем начинает вводить данные в следующее поле DataGrid, дата исчезает.

Если это ошибка, возможно, есть обходной путь. Если в моем коде что-то отсутствует или неверно, я надеюсь стать просветленным.

Я вставлю синопсис кода после шагов к проблеме. И все файлы для проекта Microsoft Visual Studio Community 2019 будут временно доступны для загрузки по адресу https://drive.google.com/file/d/121F0FigAmmyejkn6Zimd2gZ8-5WR20jm/view?usp=sharing

Установка:

Разархивируйте iacc_core.zip в каталог вашего выбор.

Подкаталог acc_db содержит MySQL схему и данные. Надеюсь, вы сможете выполнить импорт данных в MySQL Workbench, чтобы загрузить тестовую схему с тестовыми данными. Проблема может не иметь ничего общего с MySQL, поэтому привязка к чему-то другому, кроме базы данных MySQL, также может вызвать проблему.

Вам нужно будет настроить пути к каталогам и установить соединения с базой данных ( если вы используете образец базы данных).

Шаги:

  1. Скомпилировать и запустить (т.е. нажмите F5). Наблюдать: программа открывается. Фокус находится на последней строке верхнего уровня DataGrid (транзакции).

  2. Вкладка дважды, затем введите дату «20.07.2020». Обратите внимание на дату "20.07.2020", отображаемую в DataPicker.

  3. Нажмите один раз на столбец «Ref». Введите «2». Обратите внимание на проблему: дата DatePicker исчезает. Дата должна остаться.

Краткое изложение кода

Xaml:

<Window x:Class="iacc.MainWindow"
        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:iacc"
        mc:Ignorable="d"
        Title="IACC - Transaction Journal" Height="720" Width="1000" FontFamily="Times New Roman" Closing="Window_Closing" 
                     >
    
    <StackPanel Orientation="Vertical" Margin="10">
        <Label Content="_Transactions" />
        <StackPanel Orientation="Horizontal" >
            <DataGrid Name="DataGrid_Transactions" Height="186" HorizontalAlignment="Left" AutoGenerateColumns="False"
                      TabIndex="0" SelectionMode="Extended" 
                      MouseLeftButtonDown="DataGrid_Transactions_MouseLeftButtonDown" KeyDown="DataGrid_Transactions_KeyDown" 
                      InitializingNewItem="DataGrid_Transactions_InitializingNewItem" 
                       >
                
                <DataGrid.Columns >
                    <DataGridTextColumn x:Name="col_uid" Binding="{Binding uid}" Visibility="Hidden" />
                    <DataGridTemplateColumn x:Name="col_date" Header="Date" Width="100" >
                        <DataGridTemplateColumn.CellTemplate >
                            <DataTemplate >
                                <DatePicker Name="dg_tr_cell_date_picker" 
                                            SelectedDate="{Binding date_trans, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                                            ValidatesOnExceptions=True, NotifyOnValidationError=True}"
                                            TextBlock.TextAlignment="Right"     />
                                
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn x:Name="col_ref"  Binding="{Binding reference}" Header="Ref" Width="80" />
                    <DataGridTextColumn x:Name="col_contact" Binding="{Binding contact}" Header="Contact" Width="200"/>
                    <DataGridTextColumn x:Name="col_descript" Binding="{Binding description}" Header="Description" Width="300"/>
                </DataGrid.Columns>
            </DataGrid>
            <DockPanel Width="260"  >
                <TextBlock HorizontalAlignment="Right" Width="170" >
                                <Bold><Run Text="Del"/></Bold><Run Text=" Delete row"/><LineBreak/>
                                <Bold><Run Text="Shift+Tab"/></Bold><Run Text=" Pevious cell"/><LineBreak/>
                                <Bold><Run Text="Ctrl+Up"/></Bold><Run Text=" First row"/><LineBreak/>
                                <Bold><Run Text="Ctrl+Down"/></Bold><Run Text=" Last row"/><LineBreak/>
                                <LineBreak/>
                                <Bold><Run Text="Alt+Down" /></Bold><Run Text=" Open Date Picker" /><LineBreak />
                                    <Run Text="    (when focus on Date Picker)"/>
                </TextBlock>
            </DockPanel>
        </StackPanel>
        <StackPanel Orientation="Vertical" Margin="20,10,0,0" >
            <Label Content="Transaction _Lines" Width="100" HorizontalAlignment="Left"/>
            <DataGrid x:Name="DataGrid_Lines" Width="960" Height="150" TabIndex="1" AutoGenerateColumns="False" >
                <DataGrid.Columns>
                    <DataGridTextColumn x:Name="lcol_uid" Header="UID" Binding="{Binding uid}" Visibility="Hidden" />
                    <DataGridTextColumn x:Name="lcol_uid_transactions" Header="UID Trans"  Binding="{Binding uid_transaction}" Visibility="Hidden"/>
                    <DataGridTextColumn x:Name="lcol_line_num" Header="Line Num" Binding="{Binding line_num}" Visibility="Hidden" SortDirection="Ascending" />
                    <DataGridTextColumn x:Name="lcol_entity" Header="Entity" Binding="{Binding entity}" Width="100" />
                    <DataGridTextColumn x:Name="lcol_financial_stmt" Header="Fin Stmt" Binding="{Binding financial_stmt}" Width="60" />
                    <DataGridTextColumn x:Name="lcol_acct_group" Header="Account Group" Binding="{Binding acct_group}" Width="100" />
                    <DataGridTextColumn x:Name="lcol_acct_path" Header="Account Path" Binding="{Binding acct_path}" Width="300" />
                    <DataGridTextColumn x:Name="lcol_line_description" Header="Line Description" Binding="{Binding line_description}" Width="200" />
                    <DataGridTextColumn x:Name="lcol_quantity" Header="Qty" Binding="{Binding quantity}" Width="50" />
                    <DataGridTextColumn x:Name="lcol_multiplier" Header="Mult" Binding="{Binding multiplier}" Width="50" />
                    <DataGridTextColumn x:Name="lcol_amount" Header="Amount" Binding="{Binding amount}" Width="100"  />
                </DataGrid.Columns>

            </DataGrid>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0,10,0,0"  >
            <Label Content="Row" Height="25" VerticalAlignment="Top" />
            <TextBox x:Name="TextBox_trans_row" Width="50" Height="20" VerticalAlignment="Top" Margin="5,0,0,0" TabIndex="2"  />
            <Label Content="ID" Margin="10,0,0,0" />
            <TextBox x:Name="TextBox_trans_id" Width="50" Height="20" VerticalAlignment="Top" Margin="5,0,0,0" TabIndex="3"  />
            <Button x:Name="Button_update_transaction_lines" Content="_Update Transaction Lines" Height="20" VerticalAlignment="Top" Margin="20,0,0,0"
                    Click="Button_update_transaction_lines_Click" />
            <TextBox x:Name="TextBox_DragDrop_Events" Width="200" Height="250" Margin="20,0,0,0" />
        </StackPanel>
    </StackPanel>
</Window>

Код позади:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

using MySql.Data.MySqlClient;
using MySqlX.XDevAPI.Relational;

using iacc_core;



namespace iacc
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly string conn_str = "server=chevron;user id=admin;password=admin;database=indinfer_accounting;allowuservariables=True;persistsecurityinfo=True";
        private MySql_F data_transactions = null;
        private bool FirstKeyOrClick = false;

        private MySql_F data_lines = null;

        public MainWindow()
        {
            InitializeComponent();

            string sel_str = "SELECT uid, date_trans, reference, contact, description FROM transactions ORDER BY uid";
            data_transactions = MySql_F.DataGrid_CRUD_DataSource(DataGrid_Transactions, conn_str, sel_str);

            DataGrid_Transactions.Focus();
            DataGrid_Transactions.ScrollIntoView(DataGrid_Transactions.Items[Last_Index(DataGrid_Transactions.Items.Count)]);
            DataGrid_Transactions.SelectedIndex = Last_Index(DataGrid_Transactions.Items.Count);

            // Now get the detail grid working. Get the id from the *** DataTable *** that is the source for DataGrid_Transactions
        }

        private int Last_Index(int count)
        {
            return ((count <= 1) ? 0 : count - 1);
        }



        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            data_transactions.Update_Database();
        }

  
        private bool init_datagrid_transactions()
        {
            if (FirstKeyOrClick)
            {
                return false;
            }

            FirstKeyOrClick = true;

            // Give DataGrid_Transactions keyboard focus on the last row
            DataGrid_Transactions.MoveFocus(new TraversalRequest(FocusNavigationDirection.Last));

            // Cause DataGrid_Transactions to accept input on key press instead of transferring focus to next control
            Keyboard_F.SendKey(Key.Home);
            Keyboard_F.SendKey(Key.Home);

            return true;
        }

        private void DataGrid_Transactions_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (init_datagrid_transactions())
            {
                e.Handled = true;
            }
        }


        private void DataGrid_Transactions_KeyDown(object sender, KeyEventArgs e)
        {
            if (init_datagrid_transactions())
            {
                e.Handled = true;
            }
        }


        private void Button_update_transaction_lines_Click(object sender, RoutedEventArgs e)
        {
            /*
             * Get item index from DataGrid_Transactions. Use index to get ID from the bound DataTable.
             * Use function from Adapter to update DataGrid_Lines. The ID is a parameter for this.
             */

            int idx = DataGrid_Transactions.SelectedIndex;
            TextBox_trans_row.Text = idx.ToString();
            if (idx <= DataGrid_Transactions.Items.Count)
            {
                DataRow dr = data_transactions.data_table.Rows[idx];
                TextBox_trans_id.Text = dr.Field<int>("uid").ToString();

                string select_sql = 
                    "SELECT uid, uid_transaction, line_num, entity, financial_stmt, " +
                        "acct_group, acct_path, line_description, quantity, multiplier, amount " +
                    "FROM transaction_lines " +
                    "WHERE(uid_transaction = " + idx.ToString() + ") " +
                    "ORDER BY line_num";

                string insert_sql = 
                    "INSERT INTO transaction_lines " +
                        "(uid_transaction, line_num, entity, financial_stmt, acct_group, " +
                        "acct_path, line_description, quantity, multiplier, amount) " +
                    "VALUES(@uid_transaction, @line_num, @entity, @financial_stmt, @acct_group, " +
                        "@acct_path, @line_description, @quantity, @multiplier, @amount)";

                string update_sql = "UPDATE transaction_lines " +
                    "SET uid_transaction = @uid_transaction, " +
                        "line_num = @line_num, " +
                        "entity = @entity, " +
                        "financial_stmt = @financial_stmt, " +
                        "acct_group = @acct_group, " +
                        "acct_path = @acct_path, " +
                        "line_description = @line_description, " +
                        "quantity = @quantity, " +
                        "multiplier = @multiplier, " +
                        "amount = @amount " +
                    "WHERE(transaction_lines.uid = @uid)";

                string delete_sql =
                    "DELETE FROM transaction_lines " +
                    "WHERE(transaction_lines.uid = @uid)";

                data_lines = MySql_F.DataGrid_CRUD_DataSource(DataGrid_Lines, conn_str, 
                    select_sql, insert_sql, update_sql, delete_sql);
            }
        }

        private void DataGrid_Transactions_InitializingNewItem(object sender, InitializingNewItemEventArgs e)
        {

        }

        private void dg_tr_cell_date_picker_GotFocus(object sender, RoutedEventArgs e)
        {

        }
    }


}

Ответы [ 2 ]

1 голос
/ 04 августа 2020

Благодарю @ mm8 за хороший ответ. Ответ помог разработать альтернативу. Эта альтернатива позволяет кнопке DatePicker всегда отображаться. Это кажется вопросом предпочтения стиля, поскольку вы не сохраняете щелчки или нажатия клавиш с помощью этой альтернативы.

Из того же раздела кода, который опубликовал @ mm8, замените это:

            <DataGridTemplateColumn x:Name="col_date" Header="Date" Width="100" >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <DatePicker Name="dg_tr_cell_date_picker" 
                            SelectedDate="{Binding date_trans, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                            ValidatesOnExceptions=True, NotifyOnValidationError=True}"
                            TextBlock.TextAlignment="Right"  
                            IsHitTestVisible="False" Focusable="False"       />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <DatePicker Name="dg_tr_cell_date_picker" 
                            SelectedDate="{Binding date_trans, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                            ValidatesOnExceptions=True, NotifyOnValidationError=True}"
                            TextBlock.TextAlignment="Right" 
                            Background="Green"    />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>

Примечание что в первом DatePicker (CellTemplate) мне нужно было добавить

IsHitTestVisible="False" Focusable="False"

Я думаю, что IsHitTestVisible и Focusable предотвращают редактирование в нормальном режиме. Я бы поддержал чье-то объяснение почему. Кажется, это то, что удерживает DataPicker от потери данных, даже если он появляется дважды для одного и того же столбца.

Я добавил

Background="Green"

в редактируемую версию, чтобы делать переходы между редактированием и обычным режимы очевидны. Это решение работает не из-за цвета фона.

1 голос
/ 03 августа 2020

Неправильно помещать DatePicker в CellTemplate. Поля ввода должны быть помещены в CellEditingTemplate, чтобы отредактированное значение сохранялось должным образом. CellTemplate должен просто отображать текущее значение, например, используя TextBlock:

<DataGridTemplateColumn x:Name="col_date" Header="Date" Width="100" >
    <DataGridTemplateColumn.CellTemplate >
        <DataTemplate >
            <TextBlock Text="{Binding date_trans, StringFormat=MM/dd/yyyy}" TextAlignment="Right" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <DatePicker Name="dg_tr_cell_date_picker" 
                        SelectedDate="{Binding date_trans, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                           ValidatesOnExceptions=True, NotifyOnValidationError=True}"
                        TextBlock.TextAlignment="Right" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

Так работают другие типы столбцов.

...