Функциональность WPF DataGrid Navision

Я работаю над созданием DataGrid с той же функциональностью, что и Microsoft Dynamic Nav.
Это почти как электронная таблица Excel.

Идея состоит в том, что вы можете начать редактировать ячейку. После того, как вы закончите, есть несколько шагов:

  1. Содержимое ячейки проверяется по списку.
    1.1 Если список содержит указанную строку (без учета регистра), то содержимое в DataGrid заменяется строкой из списка (т. е. той, в которой регистр учитывается). справа).
    1.2 Если в списке нет строки, он покажет новую форму с возможностями, а затем использует ту, которую выберет пользователь, чтобы заменить уже введенную в DataGrid.

  2. Если пользователь ввел что-то правильно или выбрал правильное значение из списка, то DataGrid автоматически заполнит некоторые столбцы предварительно заданной строкой.

Если мы посмотрим на пример: если пользователь вводит z в столбце 1, тогда я хочу, чтобы столбец 2 стал «x», а фокус переместился на столбец 3.

DataGrid: (Before enter/Tab pressed)

[Column1] [Column2] [Column3] [Column4]
[  "a"  ] [  "b"  ] [  "c"  ] [  "d"  ]
[  "z"  ] [       ] [       ] [       ]
(focused)

DataGrid: (Afture enter/tab pressed
[Column1] [Column2] [Column3] [Column4]
[  "a"  ] [  "b"  ] [  "c"  ] [  "d"  ]
[  "z"  ] [  "x"  ] [       ] [       ]
                    (focused)

Здесь я сталкиваюсь с некоторыми проблемами:

  1. Я использую событие CellEditEnding для проверки ввода текста. Если я нахожу правильный текст, я редактирую currentItem в правильной переменной. Но теперь мне нужно вызвать dataGrid1.Items.Refresh();, а это невозможно сделать в режиме редактирования.

Мой код:

Формтест.xaml

...
<DataGrid.Columns>
    <DataGridTextColumn Header="C1" 
        Binding="{Binding c1,UpdateSourceTrigger=LostFocus}"/>
    <DataGridTextColumn Header="C2" 
        Binding="{Binding c2,UpdateSourceTrigger=LostFocus}"/>
    <DataGridTextColumn Header="C3" 
        Binding="{Binding c3,UpdateSourceTrigger=LostFocus}"/>
    <DataGridTextColumn Header="C4" 
        Binding="{Binding c4,UpdateSourceTrigger=LostFocus}"/>
    <DataGridTextColumn Header="C5" 
        Binding="{Binding c5,UpdateSourceTrigger=LostFocus}"/>
</DataGrid.Columns>
...

FormTest.xaml.cs

public FormTest()
{
    InitializeComponent();
    loadMockData();
}
private void loadMockData()
{
    dataItems = new DataItems();
    dataItems.Add(new DataItem() { c1 = "a", c2 = "b", c3 = "c", c4 = "d", c5 = "e" });
    dataItems.Add(new DataItem() { c1 = "a", c2 = "b", c3 = "c", c4 = "d", c5 = "e" });
    dataItems.Add(new DataItem() { c1 = "a", c2 = "b", c3 = "c", c4 = "d", c5 = "e" });
    dataItems.Add(new DataItem() { c1 = "a", c2 = "b", c3 = "c", c4 = "d", c5 = "e" });
    dataItems.Add(new DataItem() { c1 = "a", c2 = "b", c3 = "c", c4 = "d", c5 = "e" });

    dataGrid1.ItemsSource = dataItems;
}
private void dataGrid1_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
    TextBox editElement = e.EditingElement as TextBox;
    DataItem di = dataGrid1.CurrentItem as DataItem;
    DataGridCellInfo cell = dataGrid1.CurrentCell;
    if (e.Column.DisplayIndex == 0)
    {
        if (editElement.Text == "z")
        {
            editElement.Text = "Z"; 
            di.c1 = "Z";
            di.c2 = "X";
        }
    }
}
private void dataGrid1_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter || e.Key == Key.Tab)
    {
        dataGrid1.CommitEdit();
        DataItem di = dataGrid1.CurrentItem as DataItem;
        dataGrid1.CancelEdit();
        dataGrid1.Items.Refresh();
     }
}

private class DataItems : List<DataItem> { }
private class DataItem
{
    public int recID { get; set; }
    public String c1 { get; set; }
    public String c2 { get; set; }
    public String c3 { get; set; }
    public String c4 { get; set; }
    public String c5 { get; set; }
}

Проблемы, с которыми я сталкиваюсь в этом коде:

  1. После вызова обновления выбранная ячейка отсутствует. Это означает, что невозможно продолжить ввод данных, не используя мышь для выбора ячейки.

  2. Когда я начинаю вводить новый элемент (также известный как пустая строка) и нажимаю ввод или вкладку, dataGrid1.CancelEnding() удалит новый элемент, и строка снова станет пустой.


Вопросы

  • Можно ли редактировать содержимое сетки данных (ItemSoure и то, что отображается) без вызова Items.Refresh()?
  • Если нет, то можно ли установить фокус ячейки после выполнения Items.Refresh(). ?
  • Или есть лучший способ сделать это?

person Bartal Clementsen    schedule 19.07.2011    source источник


Ответы (1)


Я могу ответить на ваш вопрос об обновлении содержимого сетки.

Обычно нет необходимости обновлять всю сетку после изменения одного свойства. (Это также довольно расточительно, если в вашей сетке много данных.) Если ваш класс DataItem реализует INotifyPropertyChanged, и вы запускаете событие PropertyChanged каждый раз, когда изменяется значение одного из его свойств, WPF будет автоматически обновлять данные в таблице.

Эта страница в MSDN содержит пример реализации этого интерфейса, и вы можете более полный пример использования этого интерфейса можно найти здесь.

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

Вы также должны добавить Mode=TwoWay к Binding в ваших DataGridTextColumn. В противном случае, когда вы редактируете ячейку, WPF не будет обновлять соответствующий объект DataItem значениями, которые вы вводите в сетку.

Я просмотрел несколько подходов к «табуляции» во втором столбце после ввода значения в первый столбец, но, увы, мне не удалось найти ничего, что сработало.

person Luke Woodward    schedule 20.07.2011