Получить строку в датагрид
Я пытался получить строку, как это:
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(i);
TextBlock cellContent = dataGrid.Columns[0].GetCellContent(row) as TextBlock;
Но я только получил null
, Есть ли другое решение? Что я делаю неправильно?
Я хочу получить данные из моих клеток. Мои клетки - это флажки.
4 ответа
Это зависит от того, как / когда вы пытаетесь получить эти данные. WPF больше ориентирован на доступ к данным с помощью объектов, связанных в ItemsSource. Итак, если ваш ItemsSource является списком MyObject, то конкретная строка будет иметь тип MyObject вместо чистого DataRow.
Если вы получаете доступ к данным посредством нажатия на них, вы можете сделать что-то вроде этого:
var currentItem = myDataGrid.SelectedItem as MyObject;
Теперь у вас есть текущий MyObject в его первоначальной форме, а не в сетке.
Получение доступа к подходящему объекту данных для манипуляции:
Поскольку a работает с принципалом, который привязан к объекту данных, вы захотите отслеживать свои данные в чем-то вроде файла.
Например, инициализируйте поле для вашего класса MainWindow типа DataTable и назовите его как-нибудь подходящим:
public partial class MainWindow : Window
{
private DataTable _cars = new DataTable("Cars");
Затем в вашем конструкторе, после инициализации компонента Window, свяжите
DataGrid.ItemSource
в коллекцию DataTable как представление данных:
public MainWindow()
{
InitializeComponent();
dgCars.ItemsSource = _cars.AsDataView();
}
Теперь каждый раз, когда вы программно добавляете новые строки в таблицу, они будут отражаться внутри, yay! Однако вы хотите иметь возможность работать с данными из пользовательского интерфейса, так что давайте углубимся!
Работа с данными внутри, используя входные данные из пользовательского интерфейса:
Если вы хотите работать с данными, вы можете получить то, что выбрано из элементов внутри, и использовать предоставленные ими индексы, чтобы удалить элементы из, а затем повторно применить DataView. Это резюме, но я остановлюсь на деталях и завершу пример:
Нам нужно перебрать каждый элемент и проверить, выбран ли он перед выполнением нашей логики:
for (int i = 0; i < dgCars.Items.Count; i++) { if (dgCars.SelectedItems.Contains(dgCars.Items[i])) { // This is where we do the magic } }
ОДНАКО, мы не можем удалить элементы из того, что в настоящее время используется для предоставления, иначе мы столкнемся с ошибками IndexOutOfBounds (и, возможно, Enumeration), поэтому для безопасности мы будем использовать копию таблицы для работы:
DataTable result = _cars.Copy(); //New in this step for (int i = 0; i < dgCars.Items.Count; i++) { if (dgCars.SelectedItems.Contains(dgCars.Items[i])) { result.Rows.RemoveAt(i); //New in this step } }
Опять же, мы столкнемся с ошибками IndexOutOfBounds, потому что мы перебираем данные, как если бы
X
количество данных, но каждый раз, когда мы RemoveAt (i), мы перебираемX--
количество данных. Итак, добавим счет и будем отслеживать:int removed = 0; //New in this step DataTable result = _cars.Copy(); for (int i = 0; i < dgCars.Items.Count; i++) { if (dgCars.SelectedItems.Contains(dgCars.Items[i])) { //Subtracting `removed` new in this step result.Rows.RemoveAt(i - removed); removed++; //New in this step } }
И последнее, но не менее важное: мы укажем нашу переменную на наш объект DataTable в куче, а затем переназначим его для обновления нашего DataGrid (более сложное объяснение этого в самом низу моего ответа, если интересно) :
int removed = 0; DataTable result = _cars.Copy(); for (int i = 0; i < dgCars.Items.Count; i++) { if (dgCars.SelectedItems.Contains(dgCars.Items[i])) { result.Rows.RemoveAt(i - removed); removed++; } } _cars = result; //New in this step dgCars.ItemSource = _cars.AsDataView(); //New in this step
Готовый продукт:
Этот пример, который мы создали здесь, позволяет вам удалять данные из, выбирая строки на нем с помощью мыши, а затем нажимая кнопку, которая
Click
значение равно. Простые модификации и изменение логики позволят вам делать то же самое для добавления, редактирования и т. Д. Данных, но с принципом, с которого мы изначально начали, а именно: работать с объектом данных (в данном случае a) и сделать этот элемент
ItemsSource
для
DataGrid
.
public partial class MainWindow : Window
{
private DataTable _cars = new DataTable("Cars");
public MainWindow()
{
InitializeComponent();
// THIS WASN'T IN THE BUILD EXAMPLE, BUT AS A BONUS:
// We could ALSO use this opportunity to setup static
// column headers if we know what they are in advance!
_cars.Columns.Add("Year");
_cars.Columns.Add("Make");
_cars.Columns.Add("Model");
dgCars.ItemsSource = _cars.AsDataView();
}
private btnRemove_Click(object sender, RoutedEventArgs e)
{
int removed = 0;
DataTable result = _cars.Copy();
for (int i = 0; i < dgCars.Items.Count; i++)
{
if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
{
result.Rows.RemoveAt(i - removed);
removed++;
}
}
_cars = result;
dgCars.ItemSource = _cars.AsDataView();
}
}
-Дополнительное чтение-
Ранее на шаге 4 я упоминал:
И последнее, но не менее важное: мы укажем нашу переменную на наш объект DataTable в куче, а затем переназначим
dgCars.ItemSource = _cars.AsDataView()
обновить наш DataGrid
Причина в том, что оба объекта являются экземплярами класса и находятся в куче. Элементы в куче собираются сборщиком мусора (удаляются из памяти), когда на них больше нет ссылки в стеке. Поскольку это поле нашего
MainWindow
, и продолжает выходить за рамки, когда мы указываем на
DataTable result
мы сохраняем ссылку на эту таблицу и отбрасываем ссылку на исходную таблицу. Таким образом, когда
btnRemove_Click
завершается, переменная
result
сборщик мусора, старый
DataTable
ИСПОЛЬЗУЕМЫЕ для указания на сборщик мусора, и
_cars
теперь ссылается на наш новый объект DataTable, который мы создали.
В этом ответе содержится значительно более подробная информация, и комментарии к нему также стоит прочитать: qaru.site/questions/435 / ...
Может быть, кому-нибудь будет полезно:
Перед добавлением элемента в DataGrid(WPF), если вы хотите получить ненулевой DataGridRow в будущем, чтобы изменить некоторые свойства, такие как Background, вам необходимо создать новый объект DataGridRow, назначить свой класс свойству DataGridRow.Item, а затем добавить его в DataGrid .
Нравится:
DataGridRow mRow = new DataGridRow();
mRow.Item = YOUR_DATA_CLASS;
_ = datagrid.Items.Add(mRow);
for(int row =0; row < dg_CountInventory.Rows.Count; row ++) //Loop through each row
{
//Provide the Column Index and row as in Loop
TextBlock b = dg_CountInventory.Columns[1].GetCellContent(dg_CountInventory.Items[row ]) as TextBlock;
}
dg_CountInventory - это мое имя сетки. Этот код будет перебирать все записи, представленные в сетке данных и в ячейке / столбце.#