дублирование заголовка столбца из запроса в DGV C#

#c# #datagridview #nullpointerexception

#c# #datagridview #исключение nullpointerexception

Вопрос:

Я столкнулся с проблемой и ищу наилучший способ ее решения. Я программирую программу управления рабочим процессом и застрял на определенной части. По сути, у меня есть вот что. Я могу запросить все продукты и отобразить их в DGV (в классе поиска продукта. Как только они устанавливают флажок a, а затем нажимают выбранную кнопку, все продукты переносятся в другой DGV в другом классе (класс Quotes). Все это отлично работает. Проблема, с которой я сталкиваюсь, заключается в том, что если они захотят вернуться и выбрать другой элемент после его передачи в класс Quotes, заголовки столбцов будут дублироваться. ЧТОБЫ обойти это, я пытаюсь скопировать имеющиеся у меня строки (в классе кавычек DGV) в список. Затем я также хочу добавить новый выбранный элемент в список, а затем установить этот список в моем источнике данных. Я копирую всю информацию (я могу отображать значения, поскольку он копирует значения ячеек в список), он просто не отображает значения в DGV, но отображается правильное количество строк (выдает ошибку нулевой ссылки, когда я пытаюсь получить значение ячейки

Во-первых, есть ли лучший способ сделать это? Во-вторых, есть ли способ заставить это работать? Я опубликую свой код.

DataGridView targetGrid = this.Q_MatDGV; Добавление списка;

         if (material.RowSelected)
        {
            //Checks to see if there are any rows in the material DGV already.
            if (Q_MatDGV.Rows.Count > 0)
            {

                //TODO: Make it so if you have to add a new item then the column headers don't get added again.
                //I think you need to make a new array list then rebind the DGV after it's cleared out. 
                // Loop through the info that is already in the table and then you will have to get the data from the material.sourcegrid.columns and add that to the array list
                // once that is done we can then re link the dataset to the old DGV. 

                var source = new BindingSource();
                sourceGrid = this.Q_MatDGV; ;
                AddRows = new List<DataGridViewRow>();

               

                foreach (DataGridViewRow sourceRow in sourceGrid.Rows)
                {
                    if (Convert.ToBoolean(sourceRow.Cells["CheckBox"].Value) == true)
                    {
                        if (!sourceRow.IsNewRow)
                        {
                            var targetRow = (DataGridViewRow)sourceRow.Clone();

                            foreach (DataGridViewCell cell in sourceRow.Cells)
                            {
                                targetRow.Cells[cell.ColumnIndex].Value = cell.Value;
                               // MessageBox.Show(cell.Value.ToString());
                            }
                            AddRows.Add(targetRow);
                        }
                    }
                }

                foreach(DataGridViewRow row in material.SourceGrid.Rows)
                {
                    if (Convert.ToBoolean(row.Cells["CheckBox"].Value) == true)
                    {
                        AddRows.Add((DataGridViewRow)row.Clone());
                     
                    }
                }



                source.DataSource = AddRows;
               // Q_MatDGV.DataSource = null;
               // Q_MatDGV.Rows.Clear();
                Q_MatDGV.DataSource = source;
                MessageBox.Show(Q_MatDGV.Rows.Count.ToString());
                MessageBox.Show(Q_MatDGV.Rows[1].Cells[2].Value.ToString());
            }
  

Комментарии:

1. Лучший способ — использовать BindingList<T> as DataSource и никогда не взаимодействовать с DGV для операций с данными. Что делает код? Где модель данных? Что содержит DGV?

Ответ №1:

Да, есть способ получше. Создайте совершенно новый проект и вставьте его поверх конструктора Form1

     public Form1()
    {
        InitializeComponent();



        var dt = new DataTable();
        dt.Columns.Add("Name");
        dt.Columns.Add("Chosen", typeof(bool));
        dt.Rows.Add("Matthew", true);
        dt.Rows.Add("Mark", false);
        dt.Rows.Add("Luke", false);
        dt.Rows.Add("John", false);

        var nonChosenDV = new DataView(dt);
        nonChosenDV.RowFilter = "[Chosen] = false";

        var chosenDV = new DataView(dt);
        chosenDV.RowFilter = "[Chosen] = true";

        var nonChosenDgv = new DataGridView();
        nonChosenDgv.DataSource = nonChosenDV;

        var chosenDgv = new DataGridView();
        chosenDgv.DataSource = chosenDV;


        var chosenF = new Form();
        chosenF.Text = "Only the chosen ones";
        chosenF.Controls.Add(chosenDgv);
        chosenF.Show();

        var nonChosenF = new Form();
        nonChosenF.Text = "These guys don't make the cut";
        nonChosenF.Controls.Add(nonChosenDgv);
        nonChosenF.Show();


        //add a dgv to this form to show all the data all the time
        var allDgv = new DataGridView();
        allDgv.DataSource = dt; //it will bind to the dt.DefaultView by the way
        this.Controls.Add(allDgv);
        this.Text = "All the raw data";


    }
  

Здесь у нас есть немного информации для создания datatable (модели для хранения ваших данных), которая содержит несколько столбцов string / bool — для упрощения работы вам следует создать свой фактический datatable в dataset designer, но это не так легко вставить, поэтому я выбрал нетипизированный маршрут

Затем мы подключаем эту же общую модель данных к 3 различным DGV в 3 разных формах, причем каждый DGV считывает данные через другой DataView, который выполняет другую фильтрацию

Поскольку мы используем общую модель данных, изменение любого из флажков в любой таблице приводит к тому, что (когда строка фиксируется путем перехода к другой строке) состояние дел обновляется таким образом, что в одной таблице всегда отображаются истинные значения, в другой — ложные (а в одной таблице отображаются все, и вы видите, что галочки включаются и выключаются)

Я сделал это как отдельные формы, потому что вы сказали «отдельный класс» — в этом контексте нет разницы между классом и формой

Наглядный урок заключается в том, что DataGridView НЕ должен быть чем-то, во что вы засовываете свои данные. Вы храните свои данные где-то в другом месте (например, в datatable) и показываете / взаимодействуете (в смысле пользовательских кликов и типов) с ними через DGV, но если вы хотите взаимодействовать с ними программно, вы извлекаете их из datatable, а не из представления (за исключением очень особых обстоятельств).

Если вам нужно выполнить что-то вроде «доступа к текущей строке», вы делаете это через BindingSource.. Очень ограниченные обстоятельства, при которых вам может потребоваться задействовать DGV, — это для таких вещей, как, например, если пользователь выбрал 10 строк; вы получаете 10 строк и запрашиваете у них их databounditem, который выдает datarow в datatable (это дает DataRowView, который имеет .Строка, которая является потоком данных, требуется некоторое приведение). Вы не перетаскиваете данные через ячейку.Значение

Комментарии:

1. Позвольте мне убедиться, что я это понимаю. Если я использую ваш пример, то я хочу сделать, это извлечь данные из моей таблицы продуктов (из базы данных) и установить их в таблицу данных (необработанные данные). Затем оттуда, когда я хотел выбрать продукт, я мог открыть форму, выбрать эту строку, и это должно вернуть ее в основную форму? Я правильно это понимаю? Если это работает подобным образом, это действительно кажется проще.

2. Дополнительно могу я спросить, почему это плохая практика извлекать информацию из DGV вместо DataTable?

3. Довольно сложно понять, какую проблему вы на самом деле пытаетесь решить, но я предположил, что это классический пользовательский интерфейс (?) типа «вот два списка, один — «все, что вы можете выбрать», а другой — «все, что вы выбрали», и выбор чего-либо перемещает это из одного списка в другой». Пример показывает, что вы можете иметь все свои данные в одном месте и логическое значение, отслеживающее, выбрано оно или нет, и тогда в пользовательском интерфейсе есть пара элементов, которые отображают / не отображают что-либо на основе логического значения. Это создает впечатление, что он перемещается из одного списка в другой, но на самом деле он всегда находится только в одном месте

4. Находятся ли эти два списка рядом или в разных формах, одна из которых открывается и закрывается (возможно, лучше скрыть / показать, тогда мы не будем постоянно создавать что-то новое), на самом деле не имеет значения, потому что у нас нет представления о том, что у нас будет сетка, которая хранит данные здесь, и другая сетка, которая хранит данные там, и мы собираемся копировать данные из одной в другую и выполнять какой-то сложный процесс сокрытия данных в этой сетке, если мы уже скопировали их в эту сетку. Это начинает отвечать на ваш второй вопрос о том, почему мы не используем элементы управления Windows для хранения данных напрямую. Это примерно..

5. .. концепция программирования под названием MVC (не одноименный продукт Microsoft ASPNET, хотя он реализует концепцию) — у вас есть ваша модель, в которой хранятся ваши данные, устройство для их просмотра (grid) и устройство для управления ими (также часто grid, если сетка не предназначена только для чтения. Другие кнопки и т.д. Могут управлять данными). Теперь вы можете хранить данные непосредственно в сетке, но это не очень полезно и усложняет работу, потому что, когда все ориентировано на «данные здесь, показывать там, управлять в другом месте», поиск способов пойти против этого плывет вверх по течению. Подумайте об этом так..