#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>
asDataSource
и никогда не взаимодействовать с 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, если сетка не предназначена только для чтения. Другие кнопки и т.д. Могут управлять данными). Теперь вы можете хранить данные непосредственно в сетке, но это не очень полезно и усложняет работу, потому что, когда все ориентировано на «данные здесь, показывать там, управлять в другом месте», поиск способов пойти против этого плывет вверх по течению. Подумайте об этом так..