Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Windows Forms »

Обсудить на форуме Обсудить на форуме

DataGrid (Windows Form) – примеры расширения.
Табличная форма для представления и редактирования данных – одна из самых часто используемых. .NET Framework содержит достаточно мощный элемент управления DataGrid предназначенный именно для решения этой задачи. Но каким бы богато функциональным не был элемент пользовательского интерфейса, разработчик всегда захочет что-нибудь улучшить, расширить, настроить.
Взяться за подробное рассмотрение возможностей по расширенному использованию DataGrid элемента управления для построения пользовательского интерфейса в GUI приложениях меня натолкнули вопросы из форумов на сайте http://www.ishodniki.ru . Действительно, табличная форма для представления и редактирования данных – одна из самых часто используемых. .NET Framework содержит достаточно мощный элемент управления DataGrid предназначенный именно для решения этой задачи. Но каким бы богато функциональным не был элемент пользовательского интерфейса, разработчик всегда захочет что-нибудь улучшить, расширить, настроить (хорошо, если это желание возникает в ответ на запросы пользователя, а не из стремления программиста освоить новые приемы, что называется ”из любви к искусству” :-) ). DataGrid, с одной стороны, предлагает удобную объектную модель для расширения своей функциональности. В то же время, взявшись за изучение вопроса, столкнулся с тем, что в документации и в online MSDN Library явно мало описаний ”как это сделать”, относящихся к работе с DataGrid. В данной статье мы посмотрим, как решать задачу ввода в ячейку из списка текстовых значений.

DropDownListBox: Ввод данных в ячейку через ComboBox

Не самый простой пример, но, пожалуй, самый наболевший. Поэтому начнем именно с него.

Все примеры будем строить на базе данных Northwind, входящей в состав поставки любой версии Microsoft SQL Server 2000.

Итак, перед нами задача – вводить данные в ячейку из ниспадающего списка возможных значений. Попытаемся найти соответствующий стиль колонки и обнаружим, что .NET Framework предлагает только два типа колонок – DataGridTextBoxColumn , для представления и редактирования текстовых строк, и DataGridBoolColumn , для представления и редактирования булевых значений.

Придется немного потрудиться. Реализуем следующий подход: для отображения значений в колонке предоставим работать классу DataGridTextBoxColumn, а при получении фокуса на ячейку, наложим на нее ComboBox элемент управления, получим значение от пользователя, и передадим его в оригинальную ячейку DataGrid.

Итак,

1 Создадим новый Windows Application проект на C#.
2 Поместим DataGrid на форму.
3 Добавим вспомогательные элементы
 

public class Form1 : System.Windows.Forms.Form
{
//	 Добавим объекты в класс формы для получения
//     DataSet из базы данных

static SqlConnection cn = 
new SqlConnection("server=(local);Integrated Security=SSPI;" + 
	"Persist Security Info=false;database=Northwind;");
	
SqlDataAdapter daEmpoyees = 
new SqlDataAdapter("Select LastName,FirstName, TitleOfCourtesy From                    
Employees", cn);
	DataSet ds = new DataSet();

// создаем элемент ComboBox - через него будем получать 
	// значения для колонки TitleOfCourtesy 		
	// Поскольку будем передвигать ComboBox поверх активной ячейки,
	// получившей фокус для пользовательского ввода - СomboBox 
// потребуется один.
ComboBox customCombo = new ComboBox();
4. Проинициализируем объекты при загрузке формы
 
	private void Form1_Load(object sender, 

System.EventArgs e)
	{
	    // заполним DataSet  		
	    daEmpoyees.Fill(ds, "Employees");
	    // свяжем  DataGrid с DataSet
	    dataGrid1.DataSource = ds;
	    dataGrid1.DataMember = "Employees";

	    customCombo.Name = "customCombo";
	
// сделаем ComboBox пока невидимым - подождем пока ячейка
// не получит фокус
	    customCombo.Visible = false;
          // заполним возможными значениями для 
          // поля TitleOfCourtesy - форма обращения 
	    customCombo.Items.Clear();
          customCombo.Items.Add("Ms.");
          customCombo.Items.Add("Dr.");
          customCombo.Items.Add("Mrs.");
          customCombo.Items.Add("Mr.");
	    
          // добавим обработчик события изменения содержимого ComboBox 
	    // в этой процедуре будем значение, 
    // выбранное пользователем в ComboBox
	    // записывать в ячейку DataGrid
		
customCombo.TextChanged+= new EventHandler(this.combo_TextChanged);
		   
	    // установим высоту строки для DataGrid в высоту нашего ComboBox
	    dataGrid1.PreferredRowHeight = customCombo.Height;

	    // Добавим ComboBox к коллекции 
	    // подчиненных элементов управления DataGrid
          dataGrid1.Controls.Add(customCombo);
}

5. Сохраним значение, введенное пользователем через ComboBox
 
	
private void combo_TextChanged(object obj,System.EventArgs e)
	{
	  if (dataGrid1.CurrentCell.ColumnNumber == 2 )
	  {       
	    // фокус с ComboBox перемещается - спрячем его
	    customCombo.Visible = false;
	    // запомним значение, выбранное пользователем, в текущей ячейке
	    dataGrid1[dataGrid1.CurrentCell] = customCombo.Text;
	   }
}
6. Осталось позаботиться, чтобы наш ComboBoх позиционировался поверх текущей ячейки DataGrid и был видимым в момент ввода значений
 
	private void dataGrid1_Paint(object sender, 
						System.Windows.Forms.PaintEventArgs e)
	{
	    if( dataGrid1.CurrentCell.ColumnNumber == 2)
          // растянем ComboBox на ширину ячейки
	      customCombo.Width = dataGrid1.GetCurrentCellBounds().Width;
	}

	private void dataGrid1_CurrentCellChanged(object sender, 
System.EventArgs e)
	{
	   // ячейка получила фокус и если это наша колонка, нужно 
   //позиционировать ComboBox поверх ячейки и сделать его видимым
	
   if( dataGrid1.CurrentCell.ColumnNumber == 2)
	   {
		// убедимся, что ComboBox невидим
		customCombo.Visible = false;
		// установим ширину ComboBox позже в событии Paint
		// это гарантирует, что ComboBox будет всегда 
		// растягиваться правильно 
		customCombo.Width = 0;
		// позиционируем ComboBox поверх активной ячейки
		customCombo.Left = dataGrid1.GetCurrentCellBounds().Left;
		customCombo.Top = dataGrid1.GetCurrentCellBounds().Top;
		customCombo.Text = dataGrid1[dataGrid1.CurrentCell] + "";
		// теперь ComboBox готов получать ввод от пользователя
		customCombo.Visible = true;
	    }
	    else
	    {
		// это не наша колонка
		customCombo.Visible = false;
		customCombo.Width = 0;
	    }
	}

	private void dataGrid1_Click(object sender, System.EventArgs e)
	{
	    // фокус не на ячейке – спрячем ComboBox
    customCombo.Visible = false;
	    customCombo.Width = 0;
	}

	private void dataGrid1_Scroll(object sender, System.EventArgs e)
	{
	    // фокус не на ячейке – спрячем ComboBox
	    customCombo.Visible = false;
	    customCombo.Width = 0;

}

7. Запускаем проект и наслаждаемся видом нашего DataGrid
Полный исходный текст примера можно загрузить из раздела Примеры на сайте http://www.gotdotnet.ru .

Давайте добавим теперь код для сохранения наших изменений, произведенных через расширенный dataGrid в базу данных. И что бы не было совсем скучно, расширим наш пример.

DbLookup: Использование ComboBox для получения значений из справочника

Итак, усложняем задачу – хотим использовать ComboBox для заполнения ячейки DataGrid, когда возможные значения хранятся в отдельной таблице, а поле содержит идентификатор соответствующей строки справочника. Говоря коротко – хотим получить так называемый dblookup. Колонка ReportsTo, моделирующая иерархию подчиненности сотрудников - подходящий кандидат для примера.

Используем тот же подход, что и в первом примере – позиционировать ComboBox поверх редактируемой ячейки. Но колонка ReportsTo содержит идентификаторы менеджеров, а пользователь хочет видеть на экране фамилии. И это его вполне законное право. Тогда будем использовать две колонки – первая, вычисляемая, для отображения фамилий менеджеров. Именно она и будет видна в DataGrid. Вторая – поле ReportsTo, будет невидима в DataGrid но будет использоваться для изменения данных в DataSet.

Итак,

1. изменим оператор Select в конструкторе SqlDataAdapter и добавим две колонки, чтобы работать с полем ReportsTo и ID для идентификации обновляемой записи:
 

SqlDataAdapter daEmpoyees = new SqlDataAdapter(
"select e.LastName as LastName,e.FirstName as FirstName, " + 
" e.TitleOfCourtesy as TitleOfCourtesy, s.LastName as Manager," + 
"e.ReportsTo as ReportsTo,e.EmployeeID as EmployeeID " + 
" from Employees as e " +
" LEFT OUTER JOIN Employees as s on e.ReportsTo = s.EmployeeID", cn);
2. Теперь наш DataSet, a потом и DataGrid будет содержать дополнительные три колонки. Поскольку мы не хотим, чтобы пользователь видел ID служащего и ID его менеджера, мы удалим эти колонки из DataGrid в обработчике события Form_Load. Коллекция колонок для таблицы в DataGrid доступна через свойство GridColumnStyles соответствующей таблице. При добавлении DataGridTableStyle() с пустой коллекцией колонок к коллекции стилей таблиц DataGrid генерирует коллекцию колонок самостоятельно на основе связанного DataSet.
 
// 

заставим DatsGrid сгенерировать коллекцию стилей колонок
// для нашего DataSet
   dataGrid1.TableStyles.Add(new DataGridTableStyle()); 
   dataGrid1.TableStyles[0].MappingName = "Employees";
// удалим последние две колонки - EmployeeID и ReportsTo
   dataGrid1.TableStyles["Employees"].GridColumnStyles.RemoveAt(5);
   dataGrid1.TableStyles["Employees"].GridColumnStyles.RemoveAt(4);
3. Теперь займемся нашей DbLookup ячейкой. Добавим еще один ComboBox – customDbLookUp – для фокусирования поверх колонки с отображаемой фамилией менеджера. Заполнять ее будем объектами, сопоставляющим для каждого служащего его ID с LastName. Эти объекты будут экземплярами класса Employee:
 
	
public class Employee
	{
		// хранит EmployeeID и lastName
		public Employee(){}
		public Employee(string s,int i)
		{
			LastName = s;
			EmployeeID = i;
		}
		public override string ToString()
		{
		// строковое свойство по умолчанию как LastName
			return ((LastName == null)?"NULL":LastName ) ;
		}
		public string LastName;
		public int	EmployeeID;
	}

4. Завершим инициализацию второго ComboBox. Мы формируем коллекцию элементов ComboBox из наших объектов Employee. В дальнейшем это позволит просто получить ID менеджера по его фамилии и запомнить этой ID в поле ReportsTo
 
customDbLookUp.Items.Clear();
   // прочтем значения EmployeeID и LastName через SqlDataReader
   SqlCommand cmdDbLookUp = new SqlCommand("Select EmployeeID, LastName From 
Employees",cn);
   SqlDataReader rdLastNames;
   cn.Open();
   rdLastNames = cmdDbLookUp.ExecuteReader();
   // заполним ComboBox значениями
   while (rdLastNames.Read()) 
   {
customDbLookUp.Items.Add(new 
Employee(rdLastNames.GetString(1),rdLastNames.GetInt32(0)));
   }
   rdLastNames.Close();
   cn.Close();
   // Добавим ComboBox к коллекции 
   // подчиненных элементов управления DataGrid

   dataGrid1.Controls.Add(customDbLookUp);
   // добавим обработчик события изменения содержимого ComboBox 
   // в этой процедуре будем значение, выбранное пользователем в ComboBox
   // записывать в ячейку DataGrid 
customDbLookUp.TextChanged += new 
EventHandler(this.customDbLookUp_TextChanged);
Управление видимостью осуществляется в соответствующих событиях DataGrid таким же образом, как и для первого ComboBox.
5. Теперь обработаем ввод пользователя через ComboBox. Помимо изменения значения в DataGrid, ,будем менять значения поля ReportsTo в DataSet
 
private void customDbLookUp_TextChanged(object obj,System.EventArgs e)
{
if (dataGrid1.CurrentCell.ColumnNumber == 3 )
{       
// фокус с ComboBox перемещается - спрячем его
	customDbLookUp.Visible = false;
// запомним значение, выбранное пользователем, в текущей ячейке
	dataGrid1[dataGrid1.CurrentCell] =  customDbLookUp.Text;
Employee emp = (Employee)customDbLookUp.SelectedItem ;
	if( emp != null)
	{
	// изменим в DataSet значение ReportsTo
	ds.Tables["Employees"].Rows[dataGrid1.CurrentCell.RowNumber]
 ["ReportsTo"] = emp.EmployeeID;
				
}
}
}
6. Осталось совсем немного – сохранить наши изменения в базе данных и проверить результат. Не забудем создать UpdateCommand для DataAdapter (удалять и добавлять строки в нашем примере мы не будем)
 
private void Form1_Load(object sender, 

System.EventArgs e)
{
daEmpoyees.UpdateCommand = 
new SqlCommand("update Employees set LastName= @LastName,
FirstName = @FirstName, TitleOfCourtesy = @TitleOfCourtesy ,
ReportsTo = @ReportsTo where EmployeeID = @EmployeeID",cn);

daEmpoyees.UpdateCommand.Parameters.Add("@LastName", 
System.Data.SqlDbType.VarChar, 20, "LastName");
daEmpoyees.UpdateCommand.Parameters.Add("@FirstName", 
System.Data.SqlDbType.VarChar, 10, "FirstName");
daEmpoyees.UpdateCommand.Parameters.Add("@ReportsTo", 
System.Data.SqlDbType.Int, 4, "ReportsTo");
daEmpoyees.UpdateCommand.Parameters.Add("@TitleOfCourtesy", 
System.Data.SqlDbType.VarChar, 25, "TitleOfCourtesy");
daEmpoyees.UpdateCommand.Parameters.Add("@EmployeeID", 
				System.Data.SqlDbType.Int, 4, "EmployeeID");

7. Добавим две кнопки и код для обработки события нажатия на кнопки.
 
private void update_Click(object 

sender, System.EventArgs e)
{
	// сохраним изменения в базе данных
	this.daEmpoyees.Update(ds,"Employees");
}
private void refresh_Click(object sender, System.EventArgs e)
{
	//	уберем строки из DataSet
	ds.Clear();
	// и заполним его заново
	daEmpoyees.Fill(ds,"Employees");
	dataGrid1.DataMember = "Employees";
	dataGrid1.DataSource = ds; 
}

Итак, мы рассмотрели один из подходов модификации интерфейса ввода DataGrid. Есть и другие пути достижения похожих задач. Наиболее типичным представляется подход использования DataGridColumnStyle класса. Когда для создания стиля колонки, отличного от текстовой строки или булевого значения, нужно создать класс, наследуемый из DataGridColumnStyle и реализующий логику отображения и редактирования значений в ячейке. Но об этом уже в следующей статье.


Может пригодится:


Автор: dmitrys
Прочитано: 8210
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (1)

Прислал: Alex
Большой респект за статью!! Нашел то что искал!!!

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру