RowSelectionBrush and AlternatingRowStyle seem to be summing instead of RowSelectionBrush determining color
On SfDataGrid, I generally use AlternatingRowStyle to make it easier to select long rows. It looks like the AlternatingRowStyle color and the RowSelectionBrush colors are being added to form the background color of the SFDG row. I'd prefer the RowSelectionBrush to determine the color totally if the row(s) are selected.
I've tried to find another way to totally override the AlternatingRowStyle color when a row is selected - you can, for instance, put a Border in the DataTemplate of SFDG and set the border's background attribute to bind to a color in the DataSource records, and have the records track the SelectedItems list. That's sort of nasty, though. So is setting the RowSelectionBrush opacity to 100%.
I haven't been able to find a way to fire a Trigger to flip the Border between transparent and the selection color because there doesn't seem to be any sort of "IsSelected" I can use to distinguish between the two types of rows.
Is there a crafty way of doing this that isn't so non-MVVM and hack-y?
Query | Comments | |
On SfDataGrid, I generally use AlternatingRowStyle to make it easier to select long rows. It looks like the AlternatingRowStyle color and the RowSelectionBrush colors are being added to form the background color of the SFDG row. I'd prefer the RowSelectionBrush to determine the color totally if the row(s) are selected. I've tried to find another way to totally override the AlternatingRowStyle color when a row is selected - you can, for instance, put a Border in the DataTemplate of SFDG and set the border's background attribute to bind to a color in the DataSource records, and have the records track the SelectedItems list. That's sort of nasty, though. So is setting the RowSelectionBrush opacity to 100%. | We have reviewed your query and attempted to replicate the scenario based on the details you provided. However, we were unable to reproduce the reported issue. When applying both the RowSelectionBrush and the AlternatingRowStyle, the selection behavior works as expected—the two styles do not conflict, and the colors are applied correctly during selection. We have attached the sample for your reference. Kindly review it. To assist you further, we request the following additional details about your scenario: Customizations: Could you please clarify how you have applied the AlternatingRowStyle? Specifically, what colors have you assigned to the alternating row style and the RowSelectionBrush? Modified Sample: Kindly modify the attached sample to reproduce the issue on your end. If possible, please include a video or image reference to illustrate the behavior. Providing these details will help us better understand the issue and offer a more accurate and effective solution. | |
I haven't been able to find a way to fire a Trigger to flip the Border between transparent and the selection color because there doesn't seem to be any sort of "IsSelected" I can use to distinguish between the two types of rows. Is there a crafty way of doing this that isn't so non-MVVM and hack-y? | You can distinguish between selected and non-selected rows and manually applying background colors to the selected rows using the SelectionChanged event. Within this event, you can set the IsSelected property to true, which will trigger the converter. Based on the selection state, the appropriate background color can then be applied to the selected rows. Code snippet to manually apply the background for selected row:
|
If this post is helpful, please consider Accepting it as the solution so that other members can locate it more quickly.
Attachment: sample_cad69807.zip
Hi Sweatha:
Thanks for getting back to me. I'll look at the .zip today and see how yours works. My program uses a relative LOT of SfDataGrids and they all do the AlternatingRowStyle + RowSelectionBrush color mixing thing. I have to say I was surprised that occurred, since it seemed like it would take time and really not net you anything to calculate a mix color.
The second half of your reply is what I was referring to as "having the records track the SelectedItems list" in my first question. It WORKS, but it's sort of hacky, and I have to move my EF Core records to an intermediate record with a selection flag, or add a no-mapping selection flag property to the db set. I'd rather not do that.
I spent a while trying to pass in SelectedItems from the SfDataGrid as a converter parameter or by a multi-binding to a converter like the one you suggest using RelativeSource TemplatedParent to fish around in the SFDG's properties but never got it to work.
Now, are you using full saturation on your example's RowSelectionBrush? THAT works, but it results in really garish colors.
At any rate, I'll go look at the .zip today, and if I can't get anywhere I'll try to make you a demo program that demonstrates the mixing thing.
Ok. You're doing things a bit differently than I have been doing in places.
I generally use a style in the xaml for the alternating row, following other SF examples, instead of sticking it in the code-behind as a cs method. No problem, that also causes the same issue I'm seeing.
You also inserted a field into your data to track SelectedItems. I got it to work that way too when I was trying different fixes, although I used it to select a Border background. But I'm using EF Core DBSet records in most places to produce read-only SfDataGrid columns which then select an editing screen. I don't want to add a non-mapped field just for that or have to copy the dbset records out to a display record set that's exactly the same, but has "IsSelected" in it. I mean, that works, but it's hacky.
I modified your sample to permit extended selection, simplified the alternaterowselector and disabled the converter, also modified the colors a bit so it's really plain.
Run the program, and select a range of records. The selected items' rowselectionbrush doesn't override the alternatingrowstyle color, it mixes with it. I would have expected rowselectionbrush to take precedence.
I've tried several ways to pass a copy of SelectedItems in to a converter routine but so far I either can't get it or changing SelectedItems doesn't trigger a redraw.
Attachment: modified_sample_51e8b11e.zip
public class AlternateRowStyleSelector : StyleSelector { public override Style SelectStyle(object item, DependencyObject container) { // Applying alternating background for rows. var row = (item as DataRowBase).RowData; var data = row as OrderInfo; if ((container as VirtualizingCellsControl).SelectionBorderVisiblity == Visibility.Visible) { // Reset the Background color to Transparent return App.Current.Resources["rowStyle1"] as Style; } return App.Current.Resources["rowStyle2"] as Style; } } private void dataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e) { // Update the style at run time when the data row is in selection and unselection state. foreach (var item in e.RemovedItems) { dataGrid.UpdateDataRow((item as GridRowInfo).RowIndex); } foreach (var item in e.AddedItems) { dataGrid.UpdateDataRow((item as GridRowInfo).RowIndex); } } |
Attachment: sample_afb0d3a7.zip
Sweatha:
That works just fine. Wasn't aware of either SelectionBorderVisibility or UpdateDataRow, but those work just fine.
Thanks,
Thomas
Sweatha:
As a sort of follow-on to the original question, if a program fired SelectedItems.Clear() for dataGrid, would you expect the SelectionChanged event to return the underlying data record types for e instead of GridSelectionChangedEventArgs?
Thomas
- e.RemovedItems – Contains the underlying data records that were removed from the selection (in this case, all previously selected items when Clear() is called)
- e.AddedItems - Contains the underlying data records that were added to the selection (this would be empty when Clear() is called)
Sweatha:
I misstated what was happening since I did it from memory. Let's try again - if I select a different record using the mouse, e.AddedItems and e.RemovedItems return a GridRowInfo object.
If I fire SelectedItems.Clear(), I get underlying data records instead of GridRowInfo objects. This means the code you sent:
*************************************************************
private void dataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
// Update the style at run time when the data row is in selection and unselection state.
foreach (var item in e.RemovedItems)
{
dataGrid.UpdateDataRow((item as GridRowInfo).RowIndex);
}
foreach (var item in e.AddedItems)
{
dataGrid.UpdateDataRow((item as GridRowInfo).RowIndex);
}
}
***************************************************************
will throw an exception when (item as GridRowInfo) returns a null, due to it being an underlying data record and not a GridRowInfo object. Returning different object types seemed unusual there, so I wanted to see if that was an intentional choice before proceeding to deal with it in some other way. If this can occur intentionally, I'll probably recode it to test each entry in the list to be a GridRowInfo or a data record, if it's a data record I can use IndexOf() to get a RowIndex.
Thomas
Thank you for sharing the detailed information regarding the issue you are encountering. We are currently validating the issue and require some additional time for analysis. We will provide further updates by June 18, 2025.
Malini Selvarasu
Lovely! In the meantime I will use .IndexOf() to generate a RowIndex, but it would be a LOT more efficient if I didn't have to do a linear search.
Thanks,
Thomas
Thomas Brand,
We would like to let you know that Essential Studio Weekly NuGet packages v30.1.39 has been published in nuget.org with the fix for the issue "Incorrect Type of RemovedItems in SelectionChangedEventArgs when clearing selection programmatically". Please let us know if you have any concerns in this.
Root Cause Details:
While clearing the selection programmatically, we mistakenly added GridRowInfo.RowData instead of GridRowInfo to the GridSelectionChangedEventArgs.RemovedItems collection. This incorrect assignment caused the issue.
- 16 Replies
- 4 Participants
- Marked answer
-
TB Thomas Brand
- Jun 6, 2025 10:47 PM UTC
- Jul 9, 2025 01:05 PM UTC