none
вычисляемый столбец в datagridview RRS feed

  • Вопрос

  • Доброго времени суток!

    Делаю лабораторную работу по БД на MS SQL (фрагмент БД "ЕГРЮЛ").

    Cобственно саму лабу я сделал благодаря методичке. Но хотелось бы для себя шагнуть немного дальше...

    Есть 3 таблицы: LICENZ (Лицензии), LIC_ORG (лицензирующий орган), LIC_VID (лицензируемые виды деятельности)

    в таблице LICENZ отображаются данные о том, какие лицензии и кому выданы. В том числе и данные о том, каким органом, какой вид деятельности лицензирован.

    В таблице LICENZ присутствуют поля lic_org (тип int) и lic_vid (тип int), связанные с полям id_rec (тип int, Primary Key) соответстветствующих таблиц. При таком положении дел в таблице лицензий отображаются идентифицирующие коды записей связанных таблиц, что затрудняет восприятие информации. Я нашел, как добавить в datagridview несвязанный столбец и оформил его ячейки как ComboBox с выводом соответствующего столбца связанной таблицы.

    И вот тут наступил... 

    Короче... мне хочется чтобы при просмотре таблицы лицензий в несвязанный столбец подставлялось наименование лицензирующего органа, соответсвующее коду из столбца lic_org. А при изменении несвязанного столбца - в столбец lic_org подставлялся идентификатор выбранной записи таблицы LIC_ORG.

    Пока что вроде все...

    P.S. Форумы посмотрел, но или вопрос поисковику неправильно задал, или по како-то иной причине - нужного решения не нашел.

    5 ноября 2013 г. 10:20

Ответы

  • Допустим, таблицы в БД созданы и заполнены следующим образом:

    create table LIC_ORG (
    	id_rec   int primary key,
    	org_name nvarchar(30)
    )
    
    create table LIC_VID (
    	id_rec   int primary key,
    	vid_name nvarchar(30)
    )
    
    create table LICENZ (
    	id      int primary key,
    	lic_org int references LIC_ORG(id_rec),
    	lic_vid int references LIC_VID(id_rec)
    )
    
    
    insert LIC_ORG values (1, 'Банк'), (2, 'МВД'), (3, 'Минфин')
    insert LIC_VID values (11, 'xxx'), (12, 'yyy'), (13, 'zzz')
    insert LICENZ  values (111, 1, 11), (112, 2, 12), (113, 3, 13)

    Я создал простой пример. Весь код расположен в конструкторе формы, для краткости.

    На форме лишь DataGridView.

    DataSet, DataAdapter, BindingSource и прочее создаются прямо в коде, но можно и с помощью дизайнеров.

    using System.Data;
    using System.Data.SqlClient;
    using System.Windows.Forms;
    
    namespace WinForm_DGV_ComboBox_DB
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                DataSet dataSet = new DataSet();
                SqlDataAdapter dataAdapter = new SqlDataAdapter();
    
                string strConn = @"...";
                string strSelect = @"select * from LICENZ; select * from LIC_ORG; select * from LIC_VID";
    
                SqlConnection conn = new SqlConnection(strConn);
    
                dataAdapter.SelectCommand = new SqlCommand(strSelect, conn);
    
                // Маппинг делаем для того, чтобы заменить имена таблиц по умолчанию на нужные.
                dataAdapter.TableMappings.Add("Table", "LICENZ");
                dataAdapter.TableMappings.Add("Table1", "LIC_ORG");
                dataAdapter.TableMappings.Add("Table2", "LIC_VID");
    
                dataAdapter.Fill(dataSet);
    
                // Создаём внешний ключ.
                // Хотя для сути данного примера это не обязательно.
                dataSet.Relations.Add(dataSet.Tables["LIC_ORG"].Columns["id_rec"], dataSet.Tables["LICENZ"].Columns["lic_org"]);
    
                // Источник данных для таблицы LICENZ.
                BindingSource licenzSource = new BindingSource();
                licenzSource.DataSource = dataSet;
                licenzSource.DataMember = "LICENZ";
                dataGridView1.DataSource = licenzSource;
    
                // При желании можно спрятать столбец.
                //dataGridView1.Columns["lic_org"].Visible = false;
    
                // Источник данных для таблицы LIC_ORG.
                BindingSource licorgSource = new BindingSource();
                licorgSource.DataSource = dataSet;
                licorgSource.DataMember = "LIC_ORG";
    
                DataGridViewComboBoxColumn comboColumn = new DataGridViewComboBoxColumn();
                comboColumn.HeaderText = "Лицензирующий орган";
                comboColumn.DataSource = licorgSource;
    
                // DataPropertyName ссылается на внешний ключ в источнике данных LICENZ
                comboColumn.DataPropertyName = "lic_org";
    
                // DisplayMember - имя столбца в источнике данных LIC_ORG
                comboColumn.DisplayMember = "org_name";
    
                // ValueMember - первичный ключ в таблице LIC_ORG
                comboColumn.ValueMember = "id_rec";
    
                dataGridView1.Columns.Add(comboColumn);
            }
        }
    }

    Для краткости у меня все три таблицы в датасете заполняются одним запросом. Опять же для простоты кода у меня нет using'ов и Dispose'ов, что конечно же обязательно в реальном коде.

    Не сделано обновление - но это, думаю, не создаст трудностей реализовать.

    • Помечено в качестве ответа Black Scorpio 8 ноября 2013 г. 1:42
    7 ноября 2013 г. 10:27

Все ответы

  • Как я понимаю, DataGridView - это компонент Windows Forms?

    Уточните, какой язык используется? C#?

    Какая технология доступа к БД? ADO.NET + DataSet? Или какая-нибудь ORM?

    6 ноября 2013 г. 7:13
  • Как я понимаю, DataGridView - это компонент Windows Forms?

    Уточните, какой язык используется? C#?

    Какая технология доступа к БД? ADO.NET + DataSet? Или какая-нибудь ORM?

    Да, действительно речь идет про windows forms. Язык C# 2010 Express ну и сервер тоже Express 2008 R2. 

    Вот про технологию доступа не совсем понял... Я подключаю файл SQL Server (client) *.mdf далее через DataSet~ы и иже с ними.


    6 ноября 2013 г. 14:45
  • для начало вам надо не много разобраться в Connected Layer, Disconnected Layer, DataSet, DataTable, DataAdapter, может и Entity.

    Вообщем начните с DataSet, Connected Layer.

    6 ноября 2013 г. 17:11
  • если еще есть вопросы, обращайтесь сюда.
    6 ноября 2013 г. 17:12
  • для начало вам надо не много разобраться в Connected Layer, Disconnected Layer, DataSet, DataTable, DataAdapter, может и Entity.

    Вообщем начните с DataSet, Connected Layer.

    Не могу считать это ответом...

    Мне бы примерчик или хотя бы сузить круг поиска.

    А так: это как вместо того, чтобы объяснить путнику, где в лесу находится тропинка, просто махнуть на заросли. :)

    7 ноября 2013 г. 2:25

  • Вот скрин того, что я хочу. на данный момент столбцы независимы (Причем первый присутствует в таблице БД а второй только в DataGridView). Изменения в первом не влияют на значение во втором и наоборот. Я же хочу, чтобы, указав во втором столбце лицензирующий орган,  в первом получить его ID. И при открытии формы во второй столбец должно подставляться наименование конторы, соответствующее коду из столбца 1.

    Как-то так...

    7 ноября 2013 г. 2:42
  • Допустим, таблицы в БД созданы и заполнены следующим образом:

    create table LIC_ORG (
    	id_rec   int primary key,
    	org_name nvarchar(30)
    )
    
    create table LIC_VID (
    	id_rec   int primary key,
    	vid_name nvarchar(30)
    )
    
    create table LICENZ (
    	id      int primary key,
    	lic_org int references LIC_ORG(id_rec),
    	lic_vid int references LIC_VID(id_rec)
    )
    
    
    insert LIC_ORG values (1, 'Банк'), (2, 'МВД'), (3, 'Минфин')
    insert LIC_VID values (11, 'xxx'), (12, 'yyy'), (13, 'zzz')
    insert LICENZ  values (111, 1, 11), (112, 2, 12), (113, 3, 13)

    Я создал простой пример. Весь код расположен в конструкторе формы, для краткости.

    На форме лишь DataGridView.

    DataSet, DataAdapter, BindingSource и прочее создаются прямо в коде, но можно и с помощью дизайнеров.

    using System.Data;
    using System.Data.SqlClient;
    using System.Windows.Forms;
    
    namespace WinForm_DGV_ComboBox_DB
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                DataSet dataSet = new DataSet();
                SqlDataAdapter dataAdapter = new SqlDataAdapter();
    
                string strConn = @"...";
                string strSelect = @"select * from LICENZ; select * from LIC_ORG; select * from LIC_VID";
    
                SqlConnection conn = new SqlConnection(strConn);
    
                dataAdapter.SelectCommand = new SqlCommand(strSelect, conn);
    
                // Маппинг делаем для того, чтобы заменить имена таблиц по умолчанию на нужные.
                dataAdapter.TableMappings.Add("Table", "LICENZ");
                dataAdapter.TableMappings.Add("Table1", "LIC_ORG");
                dataAdapter.TableMappings.Add("Table2", "LIC_VID");
    
                dataAdapter.Fill(dataSet);
    
                // Создаём внешний ключ.
                // Хотя для сути данного примера это не обязательно.
                dataSet.Relations.Add(dataSet.Tables["LIC_ORG"].Columns["id_rec"], dataSet.Tables["LICENZ"].Columns["lic_org"]);
    
                // Источник данных для таблицы LICENZ.
                BindingSource licenzSource = new BindingSource();
                licenzSource.DataSource = dataSet;
                licenzSource.DataMember = "LICENZ";
                dataGridView1.DataSource = licenzSource;
    
                // При желании можно спрятать столбец.
                //dataGridView1.Columns["lic_org"].Visible = false;
    
                // Источник данных для таблицы LIC_ORG.
                BindingSource licorgSource = new BindingSource();
                licorgSource.DataSource = dataSet;
                licorgSource.DataMember = "LIC_ORG";
    
                DataGridViewComboBoxColumn comboColumn = new DataGridViewComboBoxColumn();
                comboColumn.HeaderText = "Лицензирующий орган";
                comboColumn.DataSource = licorgSource;
    
                // DataPropertyName ссылается на внешний ключ в источнике данных LICENZ
                comboColumn.DataPropertyName = "lic_org";
    
                // DisplayMember - имя столбца в источнике данных LIC_ORG
                comboColumn.DisplayMember = "org_name";
    
                // ValueMember - первичный ключ в таблице LIC_ORG
                comboColumn.ValueMember = "id_rec";
    
                dataGridView1.Columns.Add(comboColumn);
            }
        }
    }

    Для краткости у меня все три таблицы в датасете заполняются одним запросом. Опять же для простоты кода у меня нет using'ов и Dispose'ов, что конечно же обязательно в реальном коде.

    Не сделано обновление - но это, думаю, не создаст трудностей реализовать.

    • Помечено в качестве ответа Black Scorpio 8 ноября 2013 г. 1:42
    7 ноября 2013 г. 10:27

  •             // DataPropertyName ссылается на внешний ключ в источнике данных LICENZ
               comboColumn.DataPropertyName = "lic_org";
                // DisplayMember - имя столбца в источнике данных LIC_ORG
                comboColumn.DisplayMember = "org_name";
                // ValueMember - первичный ключ в таблице LIC_ORG
                comboColumn.ValueMember = "id_rec";

    Не сделано обновление - но это, думаю, не создаст трудностей реализовать.

    Вот эти строчки мне и помогли!!! Сделано это, правда, через конструктор, но...

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

    В DataGridView прописал обработчик события CellValueChanged - dataGridView2_CellValueChanged

    В модуле формы пропишем:   

    
    private void dataGridView2_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        DataGridView datagrid = sender as DataGridView;
        DataGridViewRow thisrow = datagrid.CurrentRow;
        if (thisrow == null)
        {
            return;
        }
        else
        {
            if (datagrid.CurrentCell.OwningColumn.Name == "licorgname")
            {
                thisrow.Cells["irlicorgDataGridViewTextBoxColumn"].Value = datagrid.CurrentCell.Value;
                datagrid.Update();
            }
            else if (datagrid.CurrentCell.OwningColumn.Name == "irlicorgDataGridViewTextBoxColumn")
            {
                thisrow.Cells["licorgname"].Value = datagrid.CurrentCell.Value;
                datagrid.Update();
            }
            thisrow.Dispose();
        }
    }

    8 ноября 2013 г. 3:01
  • Petalvik, огромное Вам спасибо!!! Вы уже не первый раз мне даете хорошие советы. :)
    8 ноября 2013 г. 3:04