48

I am seeing a lot of examples on how to style Selected rows in DataGrid such as this one:

How can I set the color of a selected row in DataGrid

Can i just disabled selected row styling? i don't want to have to override every single thing that selected row changes. Just don't want any visible changes. Gotta be easier way than to create templates..

or..

disable selecting rows, if that is easier.. but from browsing this forum that seems hacky as well

Disable selecting in WPF DataGrid

Community
  • 1
  • 1
Sonic Soul
  • 23,855
  • 37
  • 130
  • 196

7 Answers7

85

figured out the XAML to get rid of selection style.. not ideal, but close enough..

<Style x:Key="CellStyle" TargetType="{x:Type DataGridCell}">
    <Setter Property="Foreground" Value="Black" />
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="{x:Null}" />
            <Setter Property="BorderBrush" Value="{x:Null}" />
        </Trigger>
    </Style.Triggers>
</Style>
Sonic Soul
  • 23,855
  • 37
  • 130
  • 196
30

Here's what worked for me:

<DataGrid>
    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Style.Triggers>
                <Trigger Property="DataGridCell.IsSelected" Value="True">
                    <Setter Property="BorderBrush">
                        <Setter.Value>
                            <SolidColorBrush Color="Transparent"/>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Foreground"
                            Value="{DynamicResource
                                   {x:Static SystemColors.ControlTextBrushKey}}"/>
                    <Setter Property="Background">
                        <Setter.Value>
                            <SolidColorBrush Color="Transparent"/>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    <!-- ... -->
</DataGrid>
Dan Stevens
  • 6,392
  • 10
  • 49
  • 68
20

I found another way that works well for my situation. I set this style for all cells because I don't want the user to select any cells.

<Style TargetType="{x:Type DataGridCell}">
    <Setter Property="IsHitTestVisible" Value="False"/>
</Style>
Brian Ensink
  • 11,092
  • 3
  • 50
  • 63
10

I'll answer the second question first: to disable selection of rows, you could change the RowStyle of your DataGrid.

<DataGrid>
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="IsEnabled" Value="False"/>
        </Style>
    </DataGrid.RowStyle>
    <!--Other DataGrid items-->
</DataGrid>

However, this changes the text style as the row itself is now "disabled". It also doesn't negate the fact that a user can still right click on the row to select it. If you really wanted to disable any kind of interaction with the datagrid's rows, you could do the following:

<DataGrid>
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="IsHitTestVisible" Value="False"/>
        </Style>
    </DataGrid.RowStyle>
    <!--Other DataGrid items-->
</DataGrid>

As the rows are still enabled, the style of the text does not change.

Now if you wanted to only change the style of selected row but leave the functionality alone, you could do the following (which is basically the same as @Dan Stevens' answer). The ControlTextBrushKey is the brush that is used by the system to color text items. Please look at this answer for an explanation between DynamicResource and StaticResource.

<DataGrid>
    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Style.Triggers>
                <Trigger Property="DataGridCell.IsSelected" Value="True">
                    <Setter Property="BorderBrush" Value="Transparent"/>
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                    <Setter Property="Background" Value="Transparent"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    <!--Other DataGrid items-->
</DataGrid>

It is important to note that the above solution does not change the style of DataGridRowHeader when the row is selected, as can be seen below (the first row is selected).

enter image description here

Community
  • 1
  • 1
JoshuaTheMiller
  • 2,582
  • 25
  • 27
6

This is relatively straightforward:

datagrid.SelectionChanged += (obj, e) =>
  Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
    datagrid.UnselectAll()));

This disables all selection on the DataGrid.

If you don't want to disable selection entirely but just hide it you'll need to modify the template.

Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • well for one i've tried that, and it still lets me select. this kind of override prevents some selections, but not all. at least visually, i can still see the row selected. – Sonic Soul Jun 16 '10 at 02:28
  • Ok, I tried it too and discovered you have to use a Dispatcher callback. The new code in my answer actually works, but it is three lines now instead of one. Is that too "hacky" for you? The reason the BeginInvoke is required is that MultiSelector's selection change handler tries to lock in the user's selection change with its own Dispatcher callback. – Ray Burns Jun 16 '10 at 03:18
  • thanks, i appreciate your help with this. but what does number of lines have to do with "hacky" code? there reason this is hacky, is because it isnt actually disabling anything, just unselecting all every time selection changes.. and using a dispatcher invoke.. how is this not a hack? – Sonic Soul Jun 16 '10 at 19:07
  • You're right: Number of lines has nothing to do with hackiness. You're also right that reversing actions is more "hacky" then disabling them (eg if you had a "DisableSelection"). Please leave the dispatcher out of it, though: Dispatcher.BeginInvoke is a standard and very important WPF feature. BeginInvoke is MY FRIEND and I won't have you calling it hacky! YOU TAKE IT BACK THIS INSTANT OR I'LL ..... :-)) [BIG GRIN] Ok, maybe it is a little hacky. Sometimes. I hope your project goes well for you. – Ray Burns Jun 16 '10 at 20:00
  • heh. i hope he isn't to sensitive :) to be honest i am not sure how safe that call to dispatcher begininvoke is and kind of reluctant to put it in my app.. trying to disguise selected style as not selected, but not having much luck with that either, because i don't seem to be able to set Foreground/Background as transparent in selected style, so as to show the original colors (which are different for every cell in the row) cant believe this thing is causing so much grief! – Sonic Soul Jun 16 '10 at 21:05
  • 1
    also, your code doesn't seem to be working for me.. (i tried it out of curiosity) – Sonic Soul Jun 16 '10 at 21:08
  • The code I posted actually works for me, and it works completely reliably. You might try it with a plain-vanilla DataGrid with nothing but a ItemsSource and a couple of DataGridTextColumns to see if it is something you're doing or a difference between our systems. I tried this on NET Framework 3.51 SP1 with WPFToolkit Feb2010. What are you using? – Ray Burns Jun 16 '10 at 21:35
  • Dispatcher.BeginInvoke is totally safe. It introduces no threading issues whatever since it executes on the same thread. All it does is call you back at the priority you request after the last dispatcher operation has returned. I use it all the time and so do many others. You should get used to using Dispatcher.BeginInvoke if you're going to be a WPF programmer because there are lots of things you'll want it for. – Ray Burns Jun 16 '10 at 21:38
  • 1
    hmm.. correct me if im wrong but i thought BeginInvoke is the asynchronous cousin of Invoke, there by making it definitely executed on a different thread. there is no callback or thread synchronization here so i guess that shouldn't cause multi threading issues however.. – Sonic Soul Jun 17 '10 at 13:55
  • 2
    You are wrong. Dispatcher has the ability to cross threads when necessary, but will only do so if you tell it to do so by selecting a Dispatcher for a different thread than you are on. When used within a UI object like this, Dispatcher.Invoke and Dispatcher.BeginInvoke simply execute the method - one synchronously, the other asynchronously. No other thread gets involved in any way, shape, or form. Glad I could clear this up for you. I can see why you were leery of using Dispatcher.BeginInvoke because of your misunderstanding of what it did. – Ray Burns Jun 17 '10 at 14:24
  • Doesn't work for me -- with or without the Dispatcher.Invokieness -- It unselects the row so it's not blue anymore, but the cell still has a black box around it from selecting it. I can click around and choose what cell has the black box around it -- how do I disable THAT part of it? – BrainSlugs83 Nov 01 '13 at 22:11
  • [ Also -- why is Dispatcher Invoke even required? Don't UI events such as this always fire on the UI thread? -- I had the same behavior with and without BeginInvoke / Invoke. I'm pretty sure it's not required here. ] – BrainSlugs83 Nov 01 '13 at 22:11
1

For those like me who have some cells with different styles and don't want to override all styles nor add triggers to each style, this is a good bet:

<DataGrid.Resources>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.HighlightBrushKey}" 
        Color="#333333"/>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.HighlightTextBrushKey}" 
        Color="Black"/>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" 
        Color="Black"/>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" 
        Color="Black"/>
</DataGrid.Resources>

HighlightBrushKey is the highlighted border with active selection and HighlightTextBrushKey is the text color with active selection

In my case, I want inactive selection to look unselected:

InactiveSelectionHighlightBrushKey is the border when selection is inactive and InactiveSelectionHighlightTextBrushKey is the text when selection is inactive

FYI: SystemColors is a static class, part of System.Windows.Media namespace. You can inspect it and shamelessly override any color you don't like!

Benoit Dufresne
  • 318
  • 3
  • 9
  • Is there a SystemColor that I can override to change the foreground color of disabled cells globally? Thanks. – Davide Capodaglio May 03 '17 at 07:25
  • Frankly I don't know. You can type `SystemColors` in Visual Studio and then hit `alt+f12` to see all things defined there and do trial and error with colors that seem like they could be it, for example anything with "inactive" in it... – Benoit Dufresne May 04 '17 at 14:17
1
<Style TargetType="DataGridCell">
    <Style.Triggers>
        <Trigger Property="DataGridCell.IsSelected" Value="True">
            <Setter Property="BorderBrush" Value="Transparent"/> <!--Removes brush color change-->
            <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Foreground}"/> <!--Removes foregound change-->
            <Setter Property="Background" Value="Transparent"/>  <!--Removes backgound change-->
        </Trigger>
    </Style.Triggers>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/> <!--Removes dotted border when on cell selection change made by keyboard-->
</Style>

I have slightly modified Dan Stevens and JoshuaTheMiller's solutions. Use this solution if:

  • you have cells with different foreground color you should use this one approach not to reset color to SystemColors.ControlTextBrushKey but to preserve it unchanged
  • you want to disable cell (and row) selection made by mouse and keyboard
Grigoriy
  • 96
  • 6