БлогNot. Табличный редактор XML-файла на Visual Studio

Табличный редактор XML-файла на Visual Studio

Сохраняем и загружаем данные формата XML, используем набор данных DataSet, добавляем к dataGridView ограничения на вводимые данные, меняем порядок перехода по ячейкам в dataGridView.

В этой недавней статье работа с табличными компонентами библиотеки .NET уже описана, но о некоторых вещах сказано довольно лаконично:

Поэтому следует пользоваться методами объекта DataSet

Дабы не переделывать вполне законченную статью, разработаем отдельное приложение, скажем, простенький табличный редактор успеваемости студенческой группы на основе компоненты DataGridView.

Создав новый проект Windows Forms с главной формой Form1, добавим на неё компоненту DataGridView и растянем на всю форму (свойство Dock = Fill). Также добавим к проекту контекстное меню contextMenuStrip с пунктами "Добавить" и "Удалить" и укажем его в свойстве ContextMenuStrip компоненты dataGridView1.

Столбцы таблицы (фамилия, 17 граф для оценок или иных отметок, графа "зачёт") создадим программно по событию Load формы:

BaseName  = "table1.xml"; Table = gcnew DataTable(); Set = gcnew DataSet();
dataGridView1->DataSource = Table; Table->Columns->Add ("ФИО");
for (int i=1; i<=17; i++) Table->Columns->Add(""+i);
Table->Columns->Add("Итого");
Set->Tables->Add(Table); dataGridView1->DataSource = Set;
Table->TableName = "Успеваемость";
if (IO::File::Exists(BaseName) == true) { 
 Set->ReadXml (BaseName);
}
dataGridView1->DataMember = "Успеваемость"; 
for(int i=1; i<=17; i++) dataGridView1->Columns[i]->Width = 25;

Перед этим, как и в статье, пропишем в классе формы глобальные величины:

private: String ^ BaseName; //имя файла с данными
private: DataTable ^ Table; //таблица с данными
private: DataSet ^ Set; //набор для управления данными
private: String ^Val; //предыдущее значение из текущей ячейки
private: int Column; //текущий столбец
private: bool Changed; //признак изменения текущей ячейки

и будем автоматически сохранять данные при выходе из программы (событие FormClosing):

Table->TableName = "Успеваемость";
Set->WriteXml(BaseName);

По выбору пункта меню "Добавить" выполняется следующее:

DataRow ^newR = Set->Tables["Успеваемость"]->NewRow();
newR[0] = "Студент";
try {
 int i=dataGridView1->CurrentCell->RowIndex;
 Set->Tables["Успеваемость"]->Rows->InsertAt(newR,i);
 Set->Tables["Успеваемость"]->AcceptChanges();
} catch (...) {}

А пункт "Удалить" проще всего запрограммировать так:

try {
 int i=dataGridView1->CurrentCell->RowIndex;
 Set->Tables["Успеваемость"]->Rows[i]->Delete();
 Set->Tables["Успеваемость"]->AcceptChanges();
}		 
catch (...) { }

Важно, что мы не пытаемся заносить данные "напрямую в таблицу", а добавляем их в набор. Применение AcceptChanges нужно, чтобы изменение данных немедленно отобразилось в таблице.

Контроль правильности ввода (не более 1 символа в графы отметок, не более 20 символов в графы "ФИО" и "Итого") сделаем следующими обработчиками:

dataGridView1_CellBeginEdit (на начало редактирования):

Column = e->ColumnIndex; //запоминаем  столбец
Val = dataGridView1->Rows[e->RowIndex]->Cells[e->ColumnIndex]->Value->ToString();
  //что было в ячейке
Changed = false; //ячейка не изменена

dataGridView1_CellValueChanged (по изменению значения в ячейке):

String ^newVal =  
 dataGridView1->Rows[e->RowIndex]->Cells[e->ColumnIndex]->Value->ToString();
if (e->ColumnIndex>0 && e->ColumnIndex<18) { if (newVal->Length>1) newVal = Val; }
else if (newVal->Length>20) newVal = Val;
dataGridView1->Rows[e->RowIndex]->Cells[e->ColumnIndex]->Value = newVal;

dataGridView1_EditingControlShowing (для установки своих обработчиков в дополнение к стандартным обработчиками событий компоненты):

if (Column > 0 && Column < 18) {
 TextBox ^tb = (TextBox^)e->Control;
 tb->MaxLength = 1;
 tb->KeyPress += gcnew KeyPressEventHandler(this,&Form1::tb_KeyPress);
}

Наша функция – дополнение к обработке KeyPress - разрешаем буквы, цифры, Bacspace и пробел. Она не член класса формы, просто включить в код:

void tb_KeyPress(System::Object^ sender, System::Windows::Forms::KeyPressEventArgs^  e) {
 char c = e->KeyChar;
 if (!(Char::IsLetterOrDigit(c) || c==(char)Keys::Back || c==(char)Keys::Space))  e->Handled = true;
 //а вот обработчик KeyDown так не сделать
}

dataGridView1_CellLeave (покидая ячейку, изменим правила перехода к следующей: по умолчанию – вниз, а мы хотим вправо):

//конечно, "костыль", по идее, надо писать класс-наследник 
//DataGridView и там управлять клавиатурой
if (!Changed) { 
 Changed = true;
 int c = dataGridView1->CurrentCell->ColumnIndex;
 if (c == dataGridView1->Columns->Count-1) {
  SendKeys::Send("{Home}");
 }
 else {
  SendKeys::Send("{Up}");
  SendKeys::Send("{Right}");
 }
}

Всё это вместе даст более-менее адекватное редактирование. Дело в том, что DataGridView обрабатывает многие клавиши своими собственными событиями и "не пускает" коды клавиш до уровня KeyPress или KeyDown (KeyUp, вроде, выполняется).

 Скачать проект Visual C++ TableEditor4 в архиве .zip (15 Кб)

24.03.2015, 14:11 [10508 просмотров]


теги: программирование xml c++/cli

К этой статье пока нет комментариев, Ваш будет первым