There is ALWAYS a way to get it to work. It may not be obvious from the WinForms designer, but it is not too hard.
Try this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
partial class Form_1:Form
{
public Form_1()
{
InitializeComponent();
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.panel4 = new System.Windows.Forms.Panel();
this.panel3 = new System.Windows.Forms.Panel();
this.panel2 = new System.Windows.Forms.Panel();
this.panel1 = new System.Windows.Forms.Panel();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 75F));
this.tableLayoutPanel1.Controls.Add(this.panel4, 3, 0);
this.tableLayoutPanel1.Controls.Add(this.panel3, 2, 0);
this.tableLayoutPanel1.Controls.Add(this.panel2, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0);
this.tableLayoutPanel1.SetRowSpan(this.panel1, 3);//This line is the key!!!!!
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(527, 372);
this.tableLayoutPanel1.TabIndex = 0;
//
// panel4
//
this.panel4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel4.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel4.Location = new System.Drawing.Point(134, 251);
this.panel4.Name = "panel4";
this.panel4.Size = new System.Drawing.Size(390, 118);
this.panel4.TabIndex = 4;
//
// panel3
//
this.panel3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel3.Location = new System.Drawing.Point(134, 127);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(390, 118);
this.panel3.TabIndex = 3;
//
// panel2
//
this.panel2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel2.Location = new System.Drawing.Point(134, 3);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(390, 118);
this.panel2.TabIndex = 2;
//
// panel1
//
this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(3, 3);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(125, 366);
this.panel1.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(527, 372);
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "Form1";
this.Text = "Form1";
this.tableLayoutPanel1.ResumeLayout(false);
this.ResumeLayout(false);
}
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel3;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Panel panel4;
}
}
The key to get this to work is this line:
this.tableLayoutPanel1.SetRowSpan(this.panel1, 3);//This line is the key!!!!!
Доброго времени суток!
В данной статье я опишу создания своих элементов для C# Windows Form.
Для примера буду создавать таблицу со всем функционалом DataGridView. Позже перейдем на свои элементы. Создание первого элемента разобьем на несколько уроков. В данном уроке произведем от рисовку таблицы, а также: создание столбцов, строк, ячеек.
Для написания будем использовать .Net FrameWork 4.7.x, среда разработки Visual Studio 2019.
В первую очередь создадим обычный проект Windows Form. Думаю не нужно это показывать. А уже потом создаем проект «Библиотека элементов управления Windows Form»(Назовем его CustomControl).
Далее у нас будет создан файл UserControl.cs. Удаляем его и создаем обычный класс TableCustoms.cs.Наш класс будет наследоваться от класса Control.
Далее в этом же файле создадим еще несколько классов, а именно:Column,Row,Cell. Рассмотрим каждый по отдельности. Начнем с Column:
[Serializable]
public class Column
{
public string Name { get; set; } = "NameColumn";//Наименование Столбца
public string Caption { get; set; } = "CaptionColumn";//Текст заголовка
public int Width { get; set; } = 100;//Стандартная ширина
public Color Back { get; set; } = Color.White;//Цвет фона
public Column()
{
}
}
Класс Row:
[Serializable]
public class Row
{
public int Heigth { get; set; } = 20;// Высота строки
public List<Cell> Cells { get; set; } = new List<Cell>();//список ячеек
public Row()
{
}
public Row(List<Cell> cells)
{
Cells = cells;
}
}
Класс Cell(Для поддержки копирования добавляем интерфейс ICloneable):
[Serializable]
public class Cell : ICloneable
{
public object Value { get; set; } = null;//значение ячейки
public Cell()
{
}
public object Clone()
{
return MemberwiseClone();
}
}
Теперь настроим наш основной класс TableCustoms:
public class TableCustoms : Control
{
#region Перемененные
public ObservableCollection<Column> Columns { get; set; } = new ObservableCollection<Column>();//Список столбцов таблицы
private ObservableCollection<Row> rows = new ObservableCollection<Row>();//Список строк
private int countRow = 0;//количество строк
#endregion
#region Свойства
public int CountRow // гетер и сетер при увеличении переменной на N раз
{
get { return countRow; }
set
{
//При увеличении добавляем
if (value > countRow)
{
int iteration = value - countRow;
for (int i = 0; i < iteration; i++)
{
rows.Add(new Row());
}
}
//при уменьшении удаляем с конца
if (value < countRow)
{
int iteration = countRow - value;
for (int i = 0; i < iteration; i++)
{
rows.Remove(rows[rows.Count - 1]);
}
}
countRow = value;
}
}
//гетер и сетер для списка строк, будет использоваться позже
public ObservableCollection<Row> Rows
{
get { return rows; }
set { }
}
public int ColumnHeaderHeigth { get; set; } = 20;//высота шапки таблицы
public int RowHeaderWidth { get; set; } = 20;//высота заголовков строк
public Color ColumnHeaderBack { get; set; } = SystemColors.Control;//Основной цвет фона заголовков таблицы
public Color BorderColor { get; set; } = Color.Black;//Стандартный цвет границ таблицы
public bool NumerableRows { get; set; } = false;//Флаг автоматической нумерации
#endregion
//Метода изменения столбцов, будет использоваться в следующем уроке
private void EditColumn()
{
}
//Метод изменения строк
private void EditRows()
{
if (countRow < rows.Count)//Увеличение количества строк
{
rows[rows.Count - 1].Cells = CreatCells(Columns.Count);//Добавление пустых ячеек в строку
countRow++;
}
if (CountRow > rows.Count)//уменьшение количества строк
{
countRow--;
}
}
//метод создания N количества ячеек
private List<Cell> CreatCells(int Count)
{
// return Enumerable.Repeat(new Cell(), Count).ToList();
List<Cell> result = new List<Cell>();
for (int i = 0; i < Count; i++)
{
result.Add(new Cell());
}
return result;
}
public TableCustoms()
{
rows.CollectionChanged += (e, v) => EditRows();//проверка изменения списка
Columns.CollectionChanged += (e, v) => EditColumn();//проверка изменения списка
BackColor = SystemColors.AppWorkspace;//Стандартный фон
PanelTable panelTable = new PanelTable(this);//Создание основной панели
panelTable.Dock = DockStyle.Fill;//Растягиваем основную панель по Control
Controls.Add(panelTable);//Добавление панели на Control
}
}
Для того, чтобы у нас были полосы прокрутки нужно использовать ScrollableControl, поэтому создадим класс PanelTable наследуем ScrollableControl и помещаем его на Control(в следующем уроке объясню почему создаем два разных контрола, а не используем сразу ScrollableControl):
internal class PanelTable : ScrollableControl//Control со ScrolLbar
{
private TableCustoms BParent;//переменная основного класса, для работы с свойствами
public PanelTable(TableCustoms bParent)
{
HScroll = true;//Отображение ползунка по горизонтали
VScroll = true;//Отображение ползунка по вертикали
AutoScroll = true;//Автоматическое появление полос прокрутки
BParent = bParent;
}
//переопределение метода
protected override void OnPaint(PaintEventArgs e)
{
Matrix m = new Matrix();
m.Translate(this.AutoScrollPosition.X, this.AutoScrollPosition.Y, MatrixOrder.Append);
e.Graphics.Transform = m;
Graphics graf = e.Graphics;
int maxWidth = 0;//Высота AutoScrollMinSize
int maxHeight = 0;//Ширина AutoScrollMinSize
//расчитываем ширину
foreach (Column item in BParent.Columns)
{
maxWidth += item.Width;
}
//расчитываем высоту
foreach (Row item in BParent.Rows)
{
maxHeight += item.Heigth;
}
AutoScrollMinSize = new Size(maxWidth + 100, maxHeight + 100);//назначаем AutoScrollMinSize относительно этого будут появляться полосы прокрутки
graf.Clear(BParent.BackColor);
DrawHeaderColumns(graf);//Отрисовка заголовков столбцов таблицы
DrawHeaderRows(graf);//Отрисовка заголовков строк таблицы
DrawCells(graf);//Отрисовка ячеек
base.OnPaint(e);
}
/// <summary>
/// Отрисока заголовков столбцов
/// </summary>
/// <param name="graf"></param>
private void DrawHeaderColumns(Graphics graf)
{
int x = 2;
Rectangle rect;
rect = new Rectangle(x, 1, BParent.RowHeaderWidth, BParent.ColumnHeaderHeigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
x += BParent.RowHeaderWidth + 1;
foreach (Column item in BParent.Columns)
{
rect = new Rectangle(x, 1, item.Width, BParent.ColumnHeaderHeigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
if (item.Caption.Length != 0)
{
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graf.DrawString(item.Caption, new Font("Times", 9), Brushes.Black, rect, sf);
}
x += item.Width + 1;
}
}
//Отрисовка заголовков строк
private void DrawHeaderRows(Graphics graf)
{
int y = 1;
int i = 0;
Rectangle rect;
y += BParent.RowHeaderWidth + 1;
foreach (Row item in BParent.Rows)
{
rect = new Rectangle(2, y, BParent.RowHeaderWidth, item.Heigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
if (BParent.NumerableRows)
{
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graf.DrawString(i.ToString(), new Font("Times", 9), Brushes.Black, rect, sf);
}
i++;
y += item.Heigth + 1;
}
}
//отрисовка ячеек
private void DrawCells(Graphics graf)
{
int x = 2 + BParent.RowHeaderWidth + 1;
int y = 2 + BParent.ColumnHeaderHeigth;
Rectangle rect;
int i = 0;
foreach (Row itemRow in BParent.Rows)
{
foreach (Column itemColumn in BParent.Columns)
{
rect = new Rectangle(x, y, itemColumn.Width, itemRow.Heigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(Color.White), rect);
if (itemRow.Cells[i].Value != null)
{
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graf.DrawString(itemRow.Cells[i].Value.ToString(), new Font("Times", 9), Brushes.Black, rect, sf);
}
x += itemColumn.Width + 1;
i++;
}
i = 0;
y += itemRow.Heigth + 1;
x = 2 + BParent.RowHeaderWidth + 1;
}
}
}
После этого «Пересобираем проект» элемента и добавляем элемент на форму(в основном проекте):
Теперь проверим некоторые методы нашего элемента:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
tableCustoms1.Rows.Add(new Row());//добавление строки
tableCustoms1.Rows.Add(new Row());
tableCustoms1.Rows[0].Cells[0].Value = "1";//Изменение значения ячейки
tableCustoms1.Rows[1].Cells[1].Value = "2";
tableCustoms1.CountRow++;//увеличение числа строк
tableCustoms1.Rows[0].Cells[0].Value = "привет";
}
}
Запускаем наш проект:
Последнее обновление: 31.10.2015
Элемент TableLayoutPanel также переопределяет панель и располагает дочерние элементы управления в виде таблицы, где для каждого
элемента имеется своя ячейка. Если нам хочется поместить в ячейку более одного элемента, то в эту ячейку добавляется другой компонент
TableLayoutPanel, в который затем вкладываются другие элементы.
Чтобы установить нужное число строки столбцов таблицы, мы можем использовать свойства Rows и Columns соответственно. Выбрав один из этих пунктов в
окне Properties (Свойства), нам отобразится следующее окно для настройки столбцов и строк:
В поле Size Type мы можем указать размер столбцов / строк. Нам доступны три возможные варианта:
-
Absolute
: задается абсолютный размер для строк или столбцов в пикселях -
Percent
: задается относительный размер в процентах. Если нам надо создать резиновый дизайн формы, чтобы ее строки и столбцы, а также
элементы управления в ячейках таблицы автоматически масштабировались при изменении размеров формы, то нам нужно использовать именно эту опцию -
AutoSize
: высота строк и ширина столбцов задается автоматически в зависимости от размера самой большой в строке
или столбце ячейки
Также мы можем комбинировать эти значения, например, один столбец может быть фиксированным с абсолютной шириной, а остальные столбцы могут иметь
ширину в процентах.
В этом диалоговом окне мы также можем добавить или удалить строки и столбцы. В тоже время графический дизайнер в Visual Studio не всегда сразу отображает
изменения в таблице — добавление или удаление строк и столбцов, изменение их размеров, поэтому, если изменений на форме никаких не происходит, надо ее закрыть и потом
открыть заново в графическом дизайнере.
Итак, например, у меня имеется три столбца и три строки размер у которых одинаков — 33.33%. В каждую ячейку таблицы добавлена кнопка, у которой установлено свойство
Dock=Fill
.
Если я изменю размеры формы, то автоматически масштабируются и строки и столбцы вместе с заключенными в них кнопками:
Что довольно удобно для создания масштабируемых интерфейсов.
В коде динамически мы можем изменять значения столбцов и строк. Причем все столбцы представлены типом ColumnStyle,
а строки — типом RowStyle:
tableLayoutPanel1.RowStyles[0].SizeType = SizeType.Percent; tableLayoutPanel1.RowStyles[0].Height = 40; tableLayoutPanel1.ColumnStyles[0].SizeType = SizeType.Absolute; tableLayoutPanel1.ColumnStyles[0].Width = 50;
Для установки размера в ColumnStyle и RowStyle определено свойство SizeType
, которое принимает одно из значений одноименного перечисления
SizeType
Добавление элемента в контейнер TableLayoutPanel имеет свои особенности. Мы можем добавить его как в следующую свободную ячейку или можем явным
образом указать ячейку таблицы:
Button saveButton = new Button(); // добавляем кнопку в следующую свободную ячейку tableLayoutPanel1.Controls.Add(saveButton); // добавляем кнопку в ячейку (2,2) tableLayoutPanel1.Controls.Add(saveButton, 2, 2);
В данном случае добавляем кнопку в ячейку, образуемую на пересечении третьего столбца и третьей строки. Правда, если у нас нет столько строк и столбцов, то
система автоматически выберет нужную ячейку для добавления.
Создание собственного элемента на примере таблицы на C# для Windows Form
В данной статье я опишу создания своих элементов для C# Windows Form.
Для примера буду создавать таблицу со всем функционалом DataGridView. Позже перейдем на свои элементы. Создание первого элемента разобьем на несколько уроков. В данном уроке произведем от рисовку таблицы, а также: создание столбцов, строк, ячеек.
Для написания будем использовать .Net FrameWork 4.7.x, среда разработки Visual Studio 2019.
В первую очередь создадим обычный проект Windows Form. Думаю не нужно это показывать. А уже потом создаем проект «Библиотека элементов управления Windows Form»(Назовем его CustomControl).
Далее у нас будет создан файл UserControl.cs. Удаляем его и создаем обычный класс TableCustoms.cs.Наш класс будет наследоваться от класса Control.
Далее в этом же файле создадим еще несколько классов, а именно:Column,Row,Cell. Рассмотрим каждый по отдельности. Начнем с Column:
Класс Cell(Для поддержки копирования добавляем интерфейс ICloneable):
Теперь настроим наш основной класс TableCustoms:
Для того, чтобы у нас были полосы прокрутки нужно использовать ScrollableControl, поэтому создадим класс PanelTable наследуем ScrollableControl и помещаем его на Control(в следующем уроке объясню почему создаем два разных контрола, а не используем сразу ScrollableControl):
После этого «Пересобираем проект» элемента и добавляем элемент на форму(в основном проекте):
Пошаговое руководство. Создание dataTable в конструкторе наборов данных
В этом пошаговом руководстве объясняется, как создать DataTable (без TableAdapter) с помощью конструктора наборов данных. Сведения о создании таблиц данных, включая TableAdapters, см. в разделе «Создание и настройка TableAdapters».
Создание приложения Windows Forms
В Visual Studio в меню Файл выберите пункты Создать>Проект.
Разверните visual C# или Visual Basic на панели слева, а затем выберите «Рабочий стол Windows«.
В средней области выберите тип проекта приложения Windows Forms .
Назовите проект DataTableWalkthrough и нажмите кнопку «ОК«.
Проект DataTableWalkthrough создается и добавляется в обозреватель решений.
Добавление нового набора данных в приложение
В меню Проект выберите команду Добавить новый элемент.
Откроется диалоговое окно Добавление нового элемента.
На панели слева выберите «Данные«, а затем выберите DataSet в средней области.
Выберите Добавить.
Visual Studio добавляет в проект файл с именем DataSet1.xsd и открывает его в конструкторе наборов данных.
Добавление новой dataTable в набор данных
Перетащите dataTable с вкладки DataSetпанели элементов в конструктор наборов данных.
Таблица с именем DataTable1 добавляется в набор данных.
Щелкните заголовок строки DataTable1 и переименуйте ее Music .
Добавление столбцов в Таблицу данных
Щелкните правой кнопкой мыши таблицу «Музыка «. Наведите указатель на пункт «Добавить» и нажмите кнопку «Столбец«.
Присвойт столбцу SongID имя.
В окне Свойства присвойте свойству DataType значение System.Int16.
Повторите этот процесс и добавьте следующие столбцы:
Установка первичного ключа для таблицы
Все таблицы данных должны иметь первичный ключ. Первичный ключ однозначно идентифицирует определенную запись в таблице данных.
Чтобы задать первичный ключ, щелкните правой кнопкой мыши столбец SongID и выберите команду «Задать первичный ключ«. Рядом со столбцом SongID появится значок клавиши.
Сохранение проекта
Чтобы сохранить проект DataTableWalkthrough , в меню «Файл » выберите «Сохранить все«.
Создать Excel в visual studio c#
Давайте научимся быстро и просто создавать и записывать файлы Excel с помощью visual studio c#. Наше самое простое приложение Windows Forms будет брать из текстбокса текст и заносить его в первую ячейку. Статья написана специально для Сергея =).
Начать необходимо с подключения библиотеки Microsoft.Office.Interop.Excel. Выглядеть это должно так:
Если у вас при открытии обозревателя решений – Ссылки – правая кнопка – Добавить ссылку – Сборки – в списке нет Microsoft.Office.Interop.Excel, то добавьте её через Nuget. Проект – управление пакетами NuGet – в строке поиска Excel:
Теперь создайте новый проект Windows Forms и на форму закиньте текстбокс и кнопку. На кнопки кликните два раза, откроется исходный код. В самом верху допишите следующее:
А в методе button1_Click замените так:
Вот, собственно говоря и все. Текст из текстбокса запишется в ячейку A1. Обратите внимание, что папка temp на диске уже должна существовать.
Дополнение. Прочитать первую ячейку
Это тоже просто:
Автор этого материала — я — Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML — то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.
заметки, си шарп, excel
создание и заполнение таблицы программно
заполнение таблицы динамически
запись и мгновенное отображение данных
заполнение dataGridView из текстового файла
запись из dataGridView в текстовый файл
создание и заполнение таблицы программно
Скрыть
Показать
Копировать
Form1.cs
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
using
System.Windows.Forms;
namespace
_0070 {
-
public
partial
class
Form1 : Form {
-
DataGridView dataGridView1 =
new
DataGridView();
-
void
Funtcion() {
-
dataGridView1.Size =
new
Size(400, 200);
-
DataGridViewTextBoxColumn column0 =
new
DataGridViewTextBoxColumn();
-
column0.Name =
"id"
;
-
column0.HeaderText =
"ID"
;
-
DataGridViewTextBoxColumn column1 =
new
DataGridViewTextBoxColumn();
-
column1.Name =
"brand"
;
-
column1.HeaderText =
"Brand"
;
-
DataGridViewImageColumn column2 =
new
DataGridViewImageColumn();
-
column2.Name =
"image"
;
-
column2.HeaderText =
"Image"
;
-
dataGridView1.Columns.AddRange(column0, column1, column2);
-
DataGridViewCell id0 =
new
DataGridViewTextBoxCell();
-
DataGridViewCell brand0 =
new
DataGridViewTextBoxCell();
-
DataGridViewCell image0 =
new
DataGridViewImageCell();
-
id0.Value =
"1"
;
-
brand0.Value =
"BMW"
;
-
image0.Value = imageList1.Images[0];
-
DataGridViewRow row0 =
new
DataGridViewRow();
-
row0.Cells.AddRange(id0, brand0, image0);
-
dataGridView1.Rows.Add(row0);
-
DataGridViewCell id1 =
new
DataGridViewTextBoxCell();
-
DataGridViewCell brand1 =
new
DataGridViewTextBoxCell();
-
DataGridViewCell image1 =
new
DataGridViewImageCell();
-
id1.Value =
"2"
;
-
brand1.Value =
"Bentley"
;
-
image1.Value = imageList1.Images[1];
-
DataGridViewRow row1 =
new
DataGridViewRow();
-
row1.Cells.AddRange(id1, brand1, image1);
-
dataGridView1.Rows.Add(row1);
-
DataGridViewCell id2 =
new
DataGridViewTextBoxCell();
-
DataGridViewCell brand2 =
new
DataGridViewTextBoxCell();
-
DataGridViewCell image2 =
new
DataGridViewImageCell();
-
id2.Value =
"3"
;
-
brand2.Value =
"Mercedes"
;
-
image2.Value = imageList1.Images[2];
-
DataGridViewRow row2 =
new
DataGridViewRow();
-
row2.Cells.AddRange(id2, brand2, image2);
-
dataGridView1.Rows.Add(row2);
-
}
-
public
Form1() {
-
InitializeComponent();
-
this
.Controls.Add(dataGridView1);
-
Funtcion();
-
}
-
}
}
заполнение таблицы динамически
Скрыть
Показать
Копировать
Form1.cs
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
using
System.Windows.Forms;
namespace
_0071 {
-
public
partial
class
Form1 : Form {
-
int
counter = 0;
-
public
Form1() {
-
InitializeComponent();
-
}
-
private
void
buttonBrowse_Click(
object
sender, EventArgs e) {
-
openFileDialog1.Filter =
"Images (*.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.png) | *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.png"
;
-
if
(openFileDialog1.ShowDialog() == DialogResult.OK) {
-
imageList1.Images.Add(Image.FromFile(openFileDialog1.FileName));
-
}
-
}
-
private
void
buttonAdd_Click(
object
sender, EventArgs e) {
-
DataGridViewCell brand =
new
DataGridViewTextBoxCell();
-
DataGridViewCell image =
new
DataGridViewImageCell();
-
brand.Value = textBoxBrend.Text;
-
image.Value = imageList1.Images[counter++];
-
DataGridViewRow row =
new
DataGridViewRow();
-
row.Cells.AddRange(brand, image);
-
dataGridView1.Rows.Add(row);
-
textBoxBrend.Clear();
-
dataGridView1.Refresh();
-
textBoxBrend.Select();
-
}
-
private
void
buttonClear_Click(
object
sender, EventArgs e) {
-
dataGridView1.Rows.Clear();
-
}
-
}
}
запись и мгновенное отображение данных
Создайте базу данных «abc» и таблицу «Avto».
Скрыть
Показать
Копировать
*.sql
CREATE DATABASE abc GO USE abc GO CREATE TABLE [dbo].[Avto] ( [Id] INT IDENTITY (1, 1) NOT NULL, [Brand] VARCHAR (255) NOT NULL, [ImageBrand] VARBINARY (MAX) NOT NULL, [Country] VARCHAR (255) NOT NULL, [ImageCountry] IMAGE NOT NULL, CONSTRAINT [PK_Avto] PRIMARY KEY CLUSTERED ([Id] ASC) );
Скрыть
Показать
Копировать
Form1.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Data.SqlClient; using System.IO; namespace _0072 { public partial class Form1 : Form { string pathImageBrand = string.Empty; string pathImageCountry = string.Empty; public Form1() { InitializeComponent(); } //кнопка Brand / Browse private void buttonBrowseBrand_Click(object sender, EventArgs e) { openFileDialog1.Filter = "Images (*.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.png) | *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.png"; if(openFileDialog1.ShowDialog() == DialogResult.OK) { pathImageBrand = openFileDialog1.FileName.ToString(); } } //кнопка Country / Browse private void buttonBrowseCountry_Click(object sender, EventArgs e) { openFileDialog2.Filter = "Images (*.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.png) | *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.png"; if(openFileDialog2.ShowDialog() == DialogResult.OK) { pathImageCountry = openFileDialog2.FileName.ToString(); } } //кнопка Add private void buttonAdd_Click(object sender, EventArgs e) { string stringConnect = @"Data Source=BISEMMSSQLSERVER2012;Initial Catalog=abc;Integrated Security=True"; string sql = "INSERT INTO Avto VALUES("+null+" '"+textBoxBrand.Text+"', @imgBrands, '"+textBoxCountry.Text+"', @imgCountries)"; byte[] imgBrands = null; FileStream fsBrand = new FileStream(pathImageBrand, FileMode.Open, FileAccess.Read); BinaryReader brBrand = new BinaryReader(fsBrand); imgBrands = brBrand.ReadBytes((int)fsBrand.Length); byte[] imgCountries = null; FileStream fsCountry = new FileStream(pathImageCountry, FileMode.Open, FileAccess.Read); BinaryReader brCountry = new BinaryReader(fsCountry); imgCountries = brCountry.ReadBytes((int)fsCountry.Length); using(SqlConnection connect = new SqlConnection(stringConnect)) { try { connect.Open(); SqlCommand command = new SqlCommand(sql, connect); command.Parameters.Add(new SqlParameter("@imgBrands", imgBrands)); command.Parameters.Add(new SqlParameter("@imgCountries", imgCountries)); int x = command.ExecuteNonQuery(); MessageBox.Show(x.ToString() + " Record added"); } catch(Exception exc) { MessageBox.Show("Error connection with a database {0}", exc.Message); } } textBoxBrand.Clear(); textBoxCountry.Clear(); this.avtoTableAdapter.Fill(this.abcDataSet.Avto); textBoxBrand.Select(); } private void Form1_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the 'abcDataSet.Avto' table. You can move, or remove it, as needed. this.avtoTableAdapter.Fill(this.abcDataSet.Avto); } } }
База данных находится в папке «database» в архиве.
заполнение dataGridView из текстового файла
Скрыть
Показать
Копировать
Form1.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; namespace _0073 { public partial class Form1 : Form { //метод заполняет dataGridView данными из текстового файла public void Function() { DataSet ds = new DataSet(); //создаем временную таблицу ds.Tables.Add("Temp"); //путь к текстовому файлу string path = @"a.txt"; StreamReader sr = new StreamReader(path); /*создаем колонки в таблице и заполняем их названиями*/ //считываем первую строку из файла, в ней названия столбцов string firstLine = sr.ReadLine(); //массив имен колонок из файла string[] arraNameColumn = System.Text.RegularExpressions.Regex.Split(firstLine, ","); for(int i=0; i<arraNameColumn.Length; i++) { ds.Tables[0].Columns.Add(arraNameColumn[i]); } /*заполняем строки в таблице*/ string Line = sr.ReadLine(); while(Line != null) { string[] arraCell = System.Text.RegularExpressions.Regex.Split(Line, ","); ds.Tables[0].Rows.Add(arraCell); Line = sr.ReadLine(); } //привязываем dataGridView к таблице dataGridView1.DataSource = ds.Tables[0]; } public Form1() { InitializeComponent(); Function(); } } }
запись из dataGridView в текстовый файл
Скрыть
Показать
Копировать
Form1.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; namespace _0074 { public partial class Form1 : Form { string path = string.Empty; public Form1() { InitializeComponent(); } //кнопка Browse file private void button1_Click(object sender, EventArgs e) { openFileDialog1.Filter = "Text (*.txt) | *.txt"; if(openFileDialog1.ShowDialog() == DialogResult.OK) { path = openFileDialog1.FileName; } } //кнопка Record into file private void button2_Click(object sender, EventArgs e) { using(StreamWriter sw = new StreamWriter(path, true)) { for(int i = 0; i < Convert.ToInt32(dataGridView1.Rows.Count-1); i++) { sw.WriteLine(dataGridView1.Rows[i].Cells[0].Value.ToString() + "t" + dataGridView1.Rows[i].Cells[1].Value.ToString()); } } } } }
Доброго времени суток!
В данной статье я опишу создания своих элементов для C# Windows Form.
Для примера буду создавать таблицу со всем функционалом DataGridView. Позже перейдем на свои элементы. Создание первого элемента разобьем на несколько уроков. В данном уроке произведем от рисовку таблицы, а также: создание столбцов, строк, ячеек.
Для написания будем использовать .Net FrameWork 4.7.x, среда разработки Visual Studio 2019.
В первую очередь создадим обычный проект Windows Form. Думаю не нужно это показывать. А уже потом создаем проект «Библиотека элементов управления Windows Form»(Назовем его CustomControl).
Далее у нас будет создан файл UserControl.cs. Удаляем его и создаем обычный класс TableCustoms.cs.Наш класс будет наследоваться от класса Control.
Далее в этом же файле создадим еще несколько классов, а именно:Column,Row,Cell. Рассмотрим каждый по отдельности. Начнем с Column:
[Serializable]
public class Column
{
public string Name { get; set; } = "NameColumn";//Наименование Столбца
public string Caption { get; set; } = "CaptionColumn";//Текст заголовка
public int Width { get; set; } = 100;//Стандартная ширина
public Color Back { get; set; } = Color.White;//Цвет фона
public Column()
{
}
}
Класс Row:
[Serializable]
public class Row
{
public int Heigth { get; set; } = 20;// Высота строки
public List<Cell> Cells { get; set; } = new List<Cell>();//список ячеек
public Row()
{
}
public Row(List<Cell> cells)
{
Cells = cells;
}
}
Класс Cell(Для поддержки копирования добавляем интерфейс ICloneable):
[Serializable]
public class Cell : ICloneable
{
public object Value { get; set; } = null;//значение ячейки
public Cell()
{
}
public object Clone()
{
return MemberwiseClone();
}
}
Теперь настроим наш основной класс TableCustoms:
public class TableCustoms : Control
{
#region Перемененные
public ObservableCollection<Column> Columns { get; set; } = new ObservableCollection<Column>();//Список столбцов таблицы
private ObservableCollection<Row> rows = new ObservableCollection<Row>();//Список строк
private int countRow = 0;//количество строк
#endregion
#region Свойства
public int CountRow // гетер и сетер при увеличении переменной на N раз
{
get { return countRow; }
set
{
//При увеличении добавляем
if (value > countRow)
{
int iteration = value - countRow;
for (int i = 0; i < iteration; i++)
{
rows.Add(new Row());
}
}
//при уменьшении удаляем с конца
if (value < countRow)
{
int iteration = countRow - value;
for (int i = 0; i < iteration; i++)
{
rows.Remove(rows[rows.Count - 1]);
}
}
countRow = value;
}
}
//гетер и сетер для списка строк, будет использоваться позже
public ObservableCollection<Row> Rows
{
get { return rows; }
set { }
}
public int ColumnHeaderHeigth { get; set; } = 20;//высота шапки таблицы
public int RowHeaderWidth { get; set; } = 20;//высота заголовков строк
public Color ColumnHeaderBack { get; set; } = SystemColors.Control;//Основной цвет фона заголовков таблицы
public Color BorderColor { get; set; } = Color.Black;//Стандартный цвет границ таблицы
public bool NumerableRows { get; set; } = false;//Флаг автоматической нумерации
#endregion
//Метода изменения столбцов, будет использоваться в следующем уроке
private void EditColumn()
{
}
//Метод изменения строк
private void EditRows()
{
if (countRow < rows.Count)//Увеличение количества строк
{
rows[rows.Count - 1].Cells = CreatCells(Columns.Count);//Добавление пустых ячеек в строку
countRow++;
}
if (CountRow > rows.Count)//уменьшение количества строк
{
countRow--;
}
}
//метод создания N количества ячеек
private List<Cell> CreatCells(int Count)
{
// return Enumerable.Repeat(new Cell(), Count).ToList();
List<Cell> result = new List<Cell>();
for (int i = 0; i < Count; i++)
{
result.Add(new Cell());
}
return result;
}
public TableCustoms()
{
rows.CollectionChanged += (e, v) => EditRows();//проверка изменения списка
Columns.CollectionChanged += (e, v) => EditColumn();//проверка изменения списка
BackColor = SystemColors.AppWorkspace;//Стандартный фон
PanelTable panelTable = new PanelTable(this);//Создание основной панели
panelTable.Dock = DockStyle.Fill;//Растягиваем основную панель по Control
Controls.Add(panelTable);//Добавление панели на Control
}
}
Для того, чтобы у нас были полосы прокрутки нужно использовать ScrollableControl, поэтому создадим класс PanelTable наследуем ScrollableControl и помещаем его на Control(в следующем уроке объясню почему создаем два разных контрола, а не используем сразу ScrollableControl):
internal class PanelTable : ScrollableControl//Control со ScrolLbar
{
private TableCustoms BParent;//переменная основного класса, для работы с свойствами
public PanelTable(TableCustoms bParent)
{
HScroll = true;//Отображение ползунка по горизонтали
VScroll = true;//Отображение ползунка по вертикали
AutoScroll = true;//Автоматическое появление полос прокрутки
BParent = bParent;
}
//переопределение метода
protected override void OnPaint(PaintEventArgs e)
{
Matrix m = new Matrix();
m.Translate(this.AutoScrollPosition.X, this.AutoScrollPosition.Y, MatrixOrder.Append);
e.Graphics.Transform = m;
Graphics graf = e.Graphics;
int maxWidth = 0;//Высота AutoScrollMinSize
int maxHeight = 0;//Ширина AutoScrollMinSize
//расчитываем ширину
foreach (Column item in BParent.Columns)
{
maxWidth += item.Width;
}
//расчитываем высоту
foreach (Row item in BParent.Rows)
{
maxHeight += item.Heigth;
}
AutoScrollMinSize = new Size(maxWidth + 100, maxHeight + 100);//назначаем AutoScrollMinSize относительно этого будут появляться полосы прокрутки
graf.Clear(BParent.BackColor);
DrawHeaderColumns(graf);//Отрисовка заголовков столбцов таблицы
DrawHeaderRows(graf);//Отрисовка заголовков строк таблицы
DrawCells(graf);//Отрисовка ячеек
base.OnPaint(e);
}
/// <summary>
/// Отрисока заголовков столбцов
/// </summary>
/// <param name="graf"></param>
private void DrawHeaderColumns(Graphics graf)
{
int x = 2;
Rectangle rect;
rect = new Rectangle(x, 1, BParent.RowHeaderWidth, BParent.ColumnHeaderHeigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
x += BParent.RowHeaderWidth + 1;
foreach (Column item in BParent.Columns)
{
rect = new Rectangle(x, 1, item.Width, BParent.ColumnHeaderHeigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
if (item.Caption.Length != 0)
{
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graf.DrawString(item.Caption, new Font("Times", 9), Brushes.Black, rect, sf);
}
x += item.Width + 1;
}
}
//Отрисовка заголовков строк
private void DrawHeaderRows(Graphics graf)
{
int y = 1;
int i = 0;
Rectangle rect;
y += BParent.RowHeaderWidth + 1;
foreach (Row item in BParent.Rows)
{
rect = new Rectangle(2, y, BParent.RowHeaderWidth, item.Heigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
if (BParent.NumerableRows)
{
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graf.DrawString(i.ToString(), new Font("Times", 9), Brushes.Black, rect, sf);
}
i++;
y += item.Heigth + 1;
}
}
//отрисовка ячеек
private void DrawCells(Graphics graf)
{
int x = 2 + BParent.RowHeaderWidth + 1;
int y = 2 + BParent.ColumnHeaderHeigth;
Rectangle rect;
int i = 0;
foreach (Row itemRow in BParent.Rows)
{
foreach (Column itemColumn in BParent.Columns)
{
rect = new Rectangle(x, y, itemColumn.Width, itemRow.Heigth);
graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
graf.FillRectangle(new SolidBrush(Color.White), rect);
if (itemRow.Cells[i].Value != null)
{
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graf.DrawString(itemRow.Cells[i].Value.ToString(), new Font("Times", 9), Brushes.Black, rect, sf);
}
x += itemColumn.Width + 1;
i++;
}
i = 0;
y += itemRow.Heigth + 1;
x = 2 + BParent.RowHeaderWidth + 1;
}
}
}
После этого «Пересобираем проект» элемента и добавляем элемент на форму(в основном проекте):
Теперь проверим некоторые методы нашего элемента:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
tableCustoms1.Rows.Add(new Row());//добавление строки
tableCustoms1.Rows.Add(new Row());
tableCustoms1.Rows[0].Cells[0].Value = "1";//Изменение значения ячейки
tableCustoms1.Rows[1].Cells[1].Value = "2";
tableCustoms1.CountRow++;//увеличение числа строк
tableCustoms1.Rows[0].Cells[0].Value = "привет";
}
}
Запускаем наш проект:
Автор: Сидоров Артем Алексеевич
Источник
3 / 3 / 1 Регистрация: 16.04.2009 Сообщений: 127 |
|
1 |
|
03.05.2009, 17:14. Показов 41623. Ответов 11
Здравствуйте! Мне нужно в приложении Windows Forms представить результат работы программы в виде небольшой табличке, содержащей 2 столбца целых цифр. (строк порядка 10-20). Это табличка должна располагаться прямо на форме. Подскажите, как это лучше сделать? Я думаю что можно сделать многострочный элемент TextBox. Или есть более эффективные способы?
__________________
0 |
1507 / 774 / 103 Регистрация: 22.04.2008 Сообщений: 1,610 |
|
03.05.2009, 18:00 |
2 |
я вот думаю лучше через компонент DataGridView. Добавлено через 57 секунд
1 |
3 / 3 / 1 Регистрация: 16.04.2009 Сообщений: 127 |
|
03.05.2009, 18:52 [ТС] |
3 |
А у вас нет примеров работы с этом компонентом? а то я чувствую что сам не разберусь…
0 |
1507 / 774 / 103 Регистрация: 22.04.2008 Сообщений: 1,610 |
|
03.05.2009, 19:15 |
4 |
Помогу конечно Добавлено через 11 минут 53 секунды
0 |
3 / 3 / 1 Регистрация: 16.04.2009 Сообщений: 127 |
|
03.05.2009, 19:32 [ТС] |
5 |
Да, 2 матрицы Код int m1[20]; double m2[20]; Чем они заполнены писать не буду, не суть важно
0 |
MCSD: APP BUILDER 8794 / 1073 / 104 Регистрация: 17.06.2006 Сообщений: 12,603 |
|
03.05.2009, 19:43 |
6 |
PMike,
4 |
1507 / 774 / 103 Регистрация: 22.04.2008 Сообщений: 1,610 |
|
03.05.2009, 20:10 |
7 |
Просто так эти матрицы точнее векторы не предствишь в DataGridView надо чтобы
0 |
3 / 3 / 1 Регистрация: 16.04.2009 Сообщений: 127 |
|
03.05.2009, 21:15 [ТС] |
8 |
И как это сделать?
0 |
akasex 48 / 49 / 10 Регистрация: 24.12.2008 Сообщений: 75 |
||||
03.05.2009, 22:38 |
9 |
|||
int m1[20];
1 |
3 / 3 / 1 Регистрация: 16.04.2009 Сообщений: 127 |
|
04.05.2009, 08:43 [ТС] |
10 |
akasex, огромное спасибо! все работает! Добавлено через 9 минут 32 секунды
0 |
1922 / 427 / 41 Регистрация: 12.07.2007 Сообщений: 2,062 |
|
04.05.2009, 09:01 |
11 |
dataGridView1.AllowUserToAddRows = false;
2 |
3 / 3 / 1 Регистрация: 16.04.2009 Сообщений: 127 |
|
04.05.2009, 14:09 [ТС] |
12 |
А как сделать чтобы таблица по горизонтали заполняла все пространство dataGridView? Добавлено через 4 часа 57 минут 52 секунды
0 |
Привязка данных
Эта глава основана на материалах главы 26, в которой описаны различные способы извлечения и изменения данных, и посвящена представлению данных для пользователей с привязкой данных к различным элементам управления Windows. Точнее говоря, здесь будут обсуждаться следующие вопросы:
отображение данных с помощью элемента управления DataGridView;
возможности привязки данных .NET и как они работают;
как использовать проводник по серверу Server Explorer для создания соединения и генерации класса DataSet (не написав ни единой строки кода);
как использовать проверку попаданий и рефлексию строк DataGrid.
Коды примеров этой главы доступны на прилагаемом компакт-диске.
Элемент управления DataGridView
Элемент управления DataGrid, доступный начиная с ранних выпусков .NET, был вполне функциональным, но имел множество недоработок, которые делали его неподходящим для применения в коммерческих приложениях, например, отсутствовала возможность вывода графических изображений и раскрывающихся элементов, блокировка столбцов и тому подобное. Этот элемент управления был не вполне полноценным, поэтому многие независимые поставщики предлагали собственные сеточные компоненты, которые компенсировали эти недостатки и представляли гораздо более широкую функциональность.
В .NET 2.0 появился дополнительный сеточный элемент управления — DataGridView. Он восполнил многие недостатки своего предшественника и добавил важную функциональность, которая до этого была реализована лишь в продуктах независимых поставщиков.
Этот элемент оснащен такими же средствами привязки данных, как и старый DataGrid, а потому может работать совместно с классами Array, DataTable, DataView или DataSet либо компонентами, реализующими интерфейс IListSource или IList. Элемент управления DataGridView обеспечивает возможности разнообразного представления одних и тех же данных. В простейшем случае отображаемые данные (такие как из DataSet) указываются установкой значений свойств DataSource и DataMember. Отметим, что этот элемент управления не может подставляться вместо DataGrid, потому что его программный интерфейс полностью отличается от интерфейса DataGrid. К тому же он предлагает более широкие возможности, о которых мы и поговорим в этой главе.
1102 Часть V. Презентации
Отображение табличных данных
В главе 19 было представлено множество способов выбора данных и чтения их в таблицы, хотя отображались они очень примитивным способом — с использованием
Console.WriteLine().
Следующий пример демонстрирует, как извлечь данные и отобразить их в элементе управления DataGridView. Для этой цели мы создадим новое приложение DisplayTabularData, внешний вид которого показан на рис. 32.1.
Рис. 32.1. Внешний вид приложения DisplayTabularData
Это простое приложение выбирает каждую запись из таблицы Customer базы данных Northwind и отображает эти записи пользователю в элементе управления DataGridView. Ниже показан код этого примера (исключая код определения формы и элемента управления).
using System;
using System.Configuration; using System.Data;
using System.Data.Common; using System.Data.SqlClient; using System.Windows.Forms; namespace DisplayTabularData
{
partial class Form1: Form
{
public Form1()
{
InitializeComponent();
}
private void getData_Click(object sender, EventArgs e)
{
string customers = «SELECT * FROM Customers»;
using (SqlConnection con = new SqlConnection (ConfigurationManager. ConnectionStrings[«northwind»].ConnectionString))
{
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(customers, con); da.Fill(ds, «Customers»); dataGridView.AutoGenerateColumns = true; dataGridView.DataSource = ds;
dataGridView.DataMember = «Customers»;
}
}
}
}
Глава 32. Привязка данных 1103
Форма состоит из кнопки getData, в результате щелчка на которой вызывается метод getData_Click(), показанный в коде примера.
При этом конструируется объект SqlConnection, использующий свойство
ConnectionStrings класса ConfigurationManager. Далее создается набор данных и заполняется на основе таблицы базы данных с помощью объекта DataAdapter. Затем эти данные отображаются элементом управления DataGridView за счет установки свойств DataSource и DataMember.
Отметим, что свойству AutoGenerateColumns также присваивается значение true, поскольку это гарантирует, что пользователь что-то увидит. Если этот флаг не установлен, все столбцы придется создавать самостоятельно.
Источники данных
Элемент управления DataGridView предлагает гибкий способ отображения данных; в дополнение к установке DataSource равным DataSet, а DataMember — равным имени отображаемой таблицы, свойство DataSource может указывать на любой из следующих источников:
массив (визуальная таблица может быть связана с любым одномерным массивом);
DataTable;
DataView;
DataSet или DataViewManager;
компоненты, реализующие интерфейс IListSource;
компоненты, реализующие интерфейс IList;
любой обобщенный класс коллекции или объект, унаследованный от обобщенного класса коллекции.
В последующих разделах будут представлены примеры применения каждого из упомянутых источников данных.
Отображение данных из массива
На первый взгляд это кажется простым. Нужно создать массив, наполнить его некоторыми данными и установить свойство DataSource элемента управления DataGridView. Вот пример кода:
string[] stuff = new string[] {«One», «Two», «Three»}; dataGridView.DataSource = stuff;
Если источник данных включает множество возможных таблиц-кандидатов (как в случае с DataSet или DataViewManager), также понадобится установить свойство DataMember.
Можно заменить этим кодом код события getData_ Click из предыдущего примера. Проблема с этим кодом проявляется в отображении данных (рис. 32.2).
Вместо отображения строк, определенных в массиве, таблица показывает длины этих строк. Причина состоит в том, что когда массив используется в качестве источника данных для DataGridView, то он ищет первое общедоступное свойство объекта, содержаще-
гося в массиве, вместо строкового значения. Первое Рис. 32.2. Проблема, связанная (и единственное) общедоступное свойство строки — с примером кода
1104 Часть V. Презентации
это длина, потому она и отображается. Список свойств каждого класса может быть получен с помощью метода
GetProperties класса TypeDescriptor. Он возвращает коллекцию объектов PropertyDescriptor, которая затем может использоваться для отображения данных. Элемент управления .NET PropertyGrid применяет этот метод для отображения произвольных объектов.
Один из способов решения этой проблемы с отображением строк в DataGridView заключается в создании класса-оболочки:
protected class Item
{
public Item(string text)
{
_text = text;
}
public string Text
{
get{return _text;}
}
private string _text;
}
Рис. 32.3. Вывод массива объектов класса Item
На рис. 32.3 показан вывод массива объектов класса Item (который может быть и структурой), служащего источником данных.
DataTable
DataTable можно отображать в элементе управления DataGridView двумя способами:
если используется DataTable сама по себе, следует просто установить свойство DataSource элемента управления на эту таблицу;
если DataTable входит в DataSet, необходимо установить DataSource на DataSet, а свойство DataMember — равным имени DataTable внутри этого DataSet.
На рис. 32.4 показан результат запуска кода примера DataSourceDataTable. Обратите внимание на отображение последнего столбца — он показывает флаж-
ки вместо более привычных полей редактирования. Дело в том, что элемент управления DataGridView в отсутствие любой другой информации будет читать схему из источника данных (в данном случае — таблицы Products) и на основе типа столбца автоматически выбирать тип элемента управления, отображающего его. В отличие от DataGrid, DataGridView имеет встроенную поддержку столбцов с изображениями, кнопками и комбинированными списками.
Рис. 32.4. Результат запуска кода примера DataSourceDataTable
Глава 32. Привязка данных 1105
Данные в базе не изменяются, когда изменяются поля в визуальной таблице, поскольку ее данные хранятся локально на клиентском компьютере — нет никакого активного подключения к базе данных. Обновление данных в базе мы обсудим в этой главе позднее.
Отображение данных из DataView
DataView предоставляет средства фильтрации и сортировки данных внутри DataTable. Когда данные выбираются из базы, обычно пользователю разрешено сортировать их, например, щелчком на заголовке того или иного столбца. В дополнение пользователь может пожелать отфильтровать данные, чтобы показать только определенные строки, например, те, что подверглись изменениям. DataView можно фильтровать так, что только выбранные строки будут показаны пользователю; однако это не ограничивает столбцы из DataTable.
DataView не позволяет фильтровать столбцы, а только строки.
Чтобы создать DataView на базе существующей DataTable, нужно использовать следующий код:
DataView dv = new DataView(dataTable);
После создания DataView его настройки могут быть изменены. Это касается данных и допустимых действий над ними, когда они отображаются в табличном виде, например:
установка AllowEdit = false отключает всю функциональность редактирования столбцов в строках;
установка AllowNew = false отключает функциональность новых строк;
установка AllowDelete = false отключает возможность удаления строк;
установка RowStateFilter отображает только строки с заданным состоянием;
установка RowFilter позволяет фильтровать строки на основе выражений.
В следующем разделе будет показано, как использовать настройки RowFilter и RowStateFilter; остальные настройки объяснений не требуют.
Фильтрация строк на основе данных
После того, как создан DataView, данные, отображенные в этом представлении, могут быть изменены установкой свойства RowFilter. Это свойство, задаваемое строкой, применяется в качестве средства фильтрации на базе критериев, определенных значением строки. Ее синтаксис подобен конструкции WHERE стандартного SQL, но относится к данным, уже полученным из базы.
В табл. 32.1 показаны некоторые примеры конструкций фильтрации. Исполняющая система старается наилучшим образом подогнать типы данных в вы-
ражениях фильтра к соответствующим типам исходных столбцов. Например, вполне допустимо было в предыдущем примере написать UnitsInStock > ’50’ несмотря на то, что столбец имеет целочисленный тип. Если указывается неправильное выражение фильтра, это приводит к возбуждению исключения EvaluateException.
1106 Часть V. Презентации
Таблица 32.1. Примеры конструкций фильтрации
Конструкция |
Описание |
UnitsInStock > 50 |
Показывает только те строки, в которых значение столбца UnitsInStock |
больше 50. |
Client = ‘Smith’
County LIKE ‘C*’
Возвращает записи для заданного клиента.
Возвращает все записи, в которых поле Country начинается с C — в данном примере будут возвращены строки со следующими значениями
Country: Cornwall, Cumbria, Cheshire и Cambridgeshire. Символ %
может использоваться как односимвольный шаблон, в то время как * — обобщенный шаблон, которому соответствует ноль или более символов.
Фильтрация на основе состояния строк
Каждая строка внутри DataView имеет определенное состояние, которое может принимать одно из значений, перечисленных в табл. 32.2. Это состояние также может использоваться для фильтрации строк, видимых пользователю.
Таблица 32.2. Допустимые состояния строк
DataViewRowState |
Описание |
Added |
Список всех вставленных строк. |
CurrentRows |
Список всех строк за исключением удаленных. |
Deleted |
Список всех исходных строк, которые были выделены и удалены; |
вновь созданные и тут же удаленные строки не отображаются. |
|
ModifiedCurrent |
Список всех измененных строк с их текущими значениями. |
ModifiedOriginal |
Список всех измененных строк в их исходном состоянии (до изменения). |
OriginalRows |
Список всех строк, которые были изначально получены от источника дан- |
ных. Не включает новые строки. Показывает исходные значения столбцов |
|
(то есть те, что были до внесения изменений). |
|
Unchanged |
Список всех строк, которые не были изменены. |
На рис. 32.5 показана одна таблица, которая может содержать добавленные, удаленные или измененные строки, и вторая таблица, включающая строки с одним из перечисленных состояний.
Фильтр не только применяется к видимым строкам, но также и к столбцам внутри этих строк. Это наглядно демонстрирует выбор ModifiedOriginal или ModifiedCurrent. Доступные состояния описаны в главе 20 и основаны на перечислении DataRowVersion.
Например, когда пользователь обновляет столбец в строке, то эта строка будет отображена как при выборе ModifiedOriginal, так и при ModifiedCurrent; однако действительным значением будет либо исходное значение Original, полученное из базы данных (если выбрано ModifiedOriginal), либо текущее измененное значение
DataColumn (в случае выбора ModifiedCurrent).
Сортировка строк
Помимо фильтрации, данные в DataView можно также сортировать. Сортировка выполняется по возрастанию или по убыванию — простым щелчком на заголовке столбца в элементе управления DataGridView (рис. 32.6).
Глава 32. Привязка данных 1107
Рис. 32.5. Пример с двумя таблицами
Рис. 32.6. Сортировка с использованием элемента управления DataGridView
Единственная проблема состоит в том, что сортировать можно только по одному столбцу, в то время как лежащий в основе элемент управления DataView может сортировать по множеству столбцов. Когда столбец сортируется — либо щелчком на его заголовке (как показано, на столбце ProductName), либо программно — DataGrid показывает в его заголовке изображение стрелочки для пометки, по какому столбцу выполнена сортировка.
Программная установка порядка сортировки реализуется путем присвоения свойству Sort в DataView соответствующего значения:
dataView.Sort = «ProductName»;
dataView.Sort = «ProductName ASC, ProductID DESC»;
Первая строка сортирует данные по значению столбца ProductName, что можно видеть на рис. 32.6. Вторая строка сортирует данные в возрастающем порядке по
ProductName и в убывающем — по ProductID.
DataView поддерживает сортировку и по возрастанию значений столбца, и по их убыванию. Если данные в DataView отсортированы по более чем одному столбцу, то DataViewGrid перестает показывать стрелочки-символы сортировки в заголовках.
Каждый столбец в визуальной таблице может быть строго типизированным, поэтому его порядок сортировки будет основан не на строковом представлении данных столбца, а на самих данных. В результате, если в DataGrid присутствует столбец даты, то пользователь может отсортировать строки по датам, а не по их строковым представлениям (которое может иметь различный формат).
1108 Часть V. Презентации
Отображение данных из класса DataSet
Существует одно средство DataSet, которое отличает DataViewGrid от DataGrid — это когда DataSet определяет отношение между таблицами. Как в приведенных выше примерах с DataViewGrid, DataGrid может одновременно отображать только одну таблицу. Однако, как показано в следующем примере с DataSourceDataSet, можно выполнять навигацию по отношениям внутри DataSet в пределах одного экрана. Следующий код можно использовать для генерации такого DataSet на основе таблиц Customers и Orders базы данных Northwind. Этот пример загружает данные из этих двух DataTable и затем создает отношение между ними под названием CustomerOrders:
string orders = «SELECT * FROM Orders»; string customers = «SELECT * FROM Customers»;
SqlConnection conn = new SqlConnection(source); SqlDataAdapter da = new SqlDataAdapter(orders, conn); DataSet ds = new DataSet();
da.Fill(ds, «Orders»);
da = new SqlDataAdapter(customers , conn); da.Fill(ds, «Customers»); ds.Relations.Add(«CustomerOrders»,
ds.Tables[«Customers»].Columns[«CustomerID»],
ds.Tables[«Orders»].Columns[«CustomerID»]);
Созданный DataSet связывается с DataGrid простым вызовом SetDataBinding():
dataGrid1.SetDataBinding(ds, «Customers»);
Это даст вывод, показанный на рис. 32.7.
В отличие от других примеров DataGridView, приведенных с этой главе, здесь мы видим знак + слева от каждой записи. Это отражает тот факт, что DataSet имеет управляемое отношение между заказчиками и заказами. В коде можно определить любое количество таких отношений.
Когда пользователь щелкает на знаке +, отображается список отношений (или скрывается — если ранее он был отображен). Щелчок на имени отношения позволяет перейти к связанным записям (рис. 32.8); в данном примере — к списку заказов, размещенных выбранным заказчиком.
Рис. 32.7. Знаки + слева от каждой записи обозначают отношения между заказчиками и заказами
Глава 32. Привязка данных 1109
Рис. 32.8. Связанные записи, отображаемые в результате щелчка на имени отношения
Элемент управления DataGrid также включает пару новых пиктограмм в правом верхнем углу. Пиктограмма со стрелкой влево позволяет перейти к родительской записи и вернет экран к состоянию, показанному на предыдущей странице. Вторая пиктограмма служит для того, чтобы показать/скрыть детальную информацию о родительской записи в строке заголовка.
Отображение данных в DataViewManager
Отображение данных в DataViewManager — такое же, как для DataSet, показанное в предыдущем разделе. И потому для отображения только заказчиков из Великобритании (UK), содержащихся в таблице Customers, необходим следующий код:
DataViewManager dvm = new DataViewManager(ds); dvm.DataViewSettings[«Customers»].RowFilter = «Country=’UK'»; dataGrid.SetDataBinding(dvm, «Customers»);
На рис. 32.9 показан вывод примера кода DataSourceDataViewManager.
Рис. 32.9. Вывод примера кода DataSourceDataViewManager
Интерфейсы IListSource и IList
DataGridView также поддерживает любые объекты, которые реализуют интерфейсы IListSource или IList. Интерфейс IListSource имеет только один метод — GetList(), который возвращает интерфейс IList. В свою очередь, IList пред-
1110 Часть V. Презентации
ставляет собой нечто более интересное. Этот интерфейс реализуют многие классы исполняющей системы. Среди них — Array, ArrayList и StringCollection.
Когда используется IList, в силе остается то же предупреждение относительно объектов, содержащихся в коллекции, которое было упомянуто ранее в примере с Array в качестве источника данных, а именно — если источником данных DataGrid служит StringCollection, то в визуальной таблице отображаются длины строк, а не их текст, как ожидалось.
Отображение обобщенных коллекций
В дополнение к уже описанным типам, DataGridView также поддерживает привязку к обобщенным коллекциям. При этом применяется такой же синтаксис, как и в других примерах, приведенных ранее в этой главе — нужно просто установить свойство DataSource в ссылку на коллекцию, и элемент управления сгенерирует соответствующий экран.
Опять-таки, отображаемые столбцы основаны на свойствах объекта — все общедоступные читаемые поля отображаются в DataGridView. В следующем примере демонстрируется отображение списочного класса.
class PersonList : List < Person >
{
}
class Person
{
public Person( string name, Sex sex, DateTime dob )
{
_name = name; _sex = sex;
_dateOfBirth = dob;
}
public string Name
{
get { return _name; } set { _name = value; }
}
public Sex Sex
{
get { return _sex; } set { _sex = value; }
}
public DateTime DateOfBirth
{
get { return _dateOfBirth; } set { _dateOfBirth = value; }
}
private string _name; private Sex _sex;
private DateTime _dateOfBirth;
}
enum Sex
{
Male,
Female
}
Экран показывает несколько экземпляров класса Person, которые сконструированы внутри класса PersonList (рис. 32.10).