Home > Software design >  Is it possible to access a DataGridRow from its DataGrid?
Is it possible to access a DataGridRow from its DataGrid?

Time:09-17

At runtime, I would like to modify the layout (like the backgroundcolour) of a row in a DataGrid.

I was expecting something like:

DataGrid dg = ...;
...
dg.Rows[i].BackGround = ...;

To my surprise, this seems not to be possible, it goes even further:

When I hover over the word DataGrid and I press F12, I arrive at the file "C:\Users...\AppData\Local\Temp\MetadataAsSource......\DataGrid.cs", which mentions all fields and properties of the DataGrid object, but there seems not to be any DataGridRow present. I have seen solutions for this issue on the internet, but they are based on the design, configuring the DataGrid in the XAML ... (I'm finding this quite complicated).

As this is my first WPF application, I suppose my way of thinking to be in contradiction with WPF policy, and that's my question:

Apparently, modifying a part of a UI control at runtime, based on user interaction, described in simple methods (not events), seems to violate WPF policy.
Can anyone explain me why?

Edit, after some tests

I've been testing the following piece of code, as mentioned in enter image description here

(As you can see, the row, corresponding with i 12, is not visible on screen. I've done multiple tests and they all yield the same result.)

So the proposed way of working only works with rows, which are actually visible on screen. Is there a way to access the row of a DataGrid, even when it's not immediately visible on screen?

Apparently, in order to cope with that, the following setting must be done in the XAML:

<DataGrid x:Name="dg_Areas" VirtualizingStackPanel.IsVirtualizing="False" ...

CodePudding user response:

DataGrid is an ItemsControl. ItemsControl generates an item container for each data item. The default container for e.g. ListBox is ListBoxItem. For the DataGrid it's the DataGridRow.

To get the container of an item or by the item's index, you need to use the API of the ItemsControl.ItemContainerGenerator:

DataGridRow row = dataGrid.ItemContainerGenerator.ContainerFromIndex(1) as DataGridRow;
DataGridRow row = dataGrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;

The item (referenced by instance or its index) must be realized, when UI virtualization is enabled. When Ui virtualization is enabled, items are only guaranteed to be realized when the item is inside the viewport of the virtualizing control's scroll viewer.

This will be always the case when you are handling the Selector.SelectedItem of the ItemsControl (when the selection was triggered by UI user interaction).

For random access while UI vurtualization is enabled, you can realize the required virtualized container by scrolling the item model programmatically into view:

dataGrid.ScrollIntoView(item);
DataGridRow row = dataGrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;

However, the recommended approach is to avoid dealing with item containers directly. It's very rarily necessary to do so. Instead, you should handle the data model. This eliminates to deal withUI details like UI virtualization and other UI related issues.

Preferably use XAML to handle container rendering details like Background color or layout details in genetal. You have styles, templates and triggers as tools to dynamically manipulate item containers.

For example, if you need to toggle the containers Background based on a condition, you would define a trigger (examples) in XAML.

  • Related