How to get a WPF DataGrid cell to right align without making the selectable area on a new row tiny?

WpfXamlDatagrid

Wpf Problem Overview


I'm using a WPF4.0 DataGrid. When double clicking on a cell in a new row everything works fine unless I've added a cell style to that column. For example, I have a numeric column where I want the data right aligned so the xaml looks like this

<DataGridTextColumn Binding="{Binding Path=ImpaId}"
                    CellStyle="{StaticResource CellRightAlign}">
     <DataGridTextColumn.Header>
          <TextBlock  Style="{StaticResource DataGridHeader}">Impa</TextBlock>
     </DataGridTextColumn.Header>
</DataGridTextColumn>

Where the style in a shared resource is just:

<Style x:Key="CellRightAlign">
    <Setter Property="Control.HorizontalAlignment"
            Value="Right" />
</Style>

The resulting selectable area on a new row is shown in the image as that small blue area.This is a very small target for the user to hit, and this happens to be the most likely column they will want to start with on a new row.

DataGrid cell with tiny width

If I remove the CellStyle, the area works as desired but of course I lose the right alignment.

DataGrid cell with proper width

Does anyone know how to achieve both?

Things I tried

  1. Setting TargetNullValue on the binding to a format with some width. This works on existing rows but has no effect on a new row.
  2. Setting MinWidth on the column, this did not affect the width of the new row selectable area.

Thing that worked:

Using the information from the answer by @AngelWPF I was able to change from using CellStyle to using ElementStyle as follows:

<DataGridTextColumn Binding="{Binding Path=ImpaId}"
                    CellStyle="{StaticResource CellRightAlign}">
    

Became

<DataGridTextColumn Binding="{Binding Path=ImpaId}"
                    ElementStyle="{StaticResource CellRightAlign}">

    

Wpf Solutions


Solution 1 - Wpf

You could apply ElementStyle on the DataGridTextColumn targetted to TextBlock and right align that, it would work.

      <DataGridTextColumn Binding="{Binding Path=ImpaId}">
          <DataGridTextColumn.Header>
               <TextBlock  Style="{StaticResource
                                  DataGridHeader}">
                    Impa
               </TextBlock>
          </DataGridTextColumn.Header>
          <DataGridTextColumn.ElementStyle>
              <Style TargetType="{x:Type TextBlock}">
                  <Setter Property="HorizontalAlignment" Value="Right" />
              </Style>
          </DataGridTextColumn.ElementStyle>
      </DataGridTextColumn> 

Solution 2 - Wpf

Just wanted to add to more examples for future code searches.

I put this in the top of the xaml file:

<UserControl.Resources>
    <Style TargetType="{x:Type TextBlock}" x:Key="RightCell">
        <Setter Property="Background" Value="{Binding Included, Converter={StaticResource BoolToColorConverter}}"/>
        <Setter Property="HorizontalAlignment" Value="Stretch"/>
        <Setter Property="TextAlignment" Value="Right"/>
    </Style>
</UserControl.Resources>

And then in the datagrid:

<DataGridTextColumn Header="Excluded" Binding="{Binding Excluded}" ElementStyle="{StaticResource RightCell}"/>

This right aligns the text and sorting is still enabled. The textbox fills the cell and in this case is colored using a bool converter.

Solution 3 - Wpf

You can try a work around :

           <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Grid Background="White" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <TextBlock HorizontalAlignment="Right" Text="{Binding Path=ImpaId}"/>
                    </Grid>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

Solution 4 - Wpf

I just had a similar problem and found another solution by overwriting the Style for the DataGridCell in Blend.

The changed items from the original style are the setters for VerticalAlignment and VerticalContentAlignment in the Style itself to stretch the cell itself and VerticalAlignment="Center" and HorizontalAlignment="Right" in the Template property to align the content. Change these values to whatever you need to align the cells content.

The rest of the style could be removed so that the settings from the base style will be used (using the StaticResource the style is BasedOn). However I left the style as Blend produced it.

This resulting XAML-Code should then be included into the controls resources:

<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource ResourceKey={x:Type DataGridCell}}">
	<Setter Property="VerticalAlignment" Value="Stretch" />
	<Setter Property="VerticalContentAlignment" Value="Stretch" />
	
	<!-- Additional styles, can be removed to fall back to base styles -->
	<Setter Property="Background" Value="Transparent"/>
	<Setter Property="BorderBrush" Value="Transparent"/>
	<Setter Property="BorderThickness" Value="1"/>
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="{x:Type DataGridCell}">
				<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
					<ContentPresenter
						ContentTemplate="{TemplateBinding ContentTemplate}"
						Content="{TemplateBinding Content}"
						ContentStringFormat="{TemplateBinding ContentStringFormat}"
						SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
						VerticalAlignment="Center"
						HorizontalAlignment="Right"
						/>
				</Border>
			</ControlTemplate>
		</Setter.Value>
	</Setter>
	<Style.Triggers>
		<Trigger Property="IsSelected" Value="True">
			<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
			<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
			<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
		</Trigger>
		<Trigger Property="IsKeyboardFocusWithin" Value="True">
			<Setter Property="BorderBrush" Value="{DynamicResource {ComponentResourceKey ResourceId=FocusBorderBrushKey, TypeInTargetAssembly={x:Type DataGrid}}}"/>
		</Trigger>
	</Style.Triggers>
</Style>

Solution 5 - Wpf

I had the same issue and got it solved now. If you want to do it inside the c# code, you need to set a bunch of setters:

DataGridTextColumn numColumn = new DataGridTextColumn
Style s = new Style();
s.Setters.Add(new Setter(HorizontalAlignmentProperty, HorizontalAlignment.Stretch));
s.Setters.Add(new Setter(HorizontalContentAlignmentProperty, HorizontalAlignment.Right));
s.Setters.Add(new Setter(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Stretch));
s.Setters.Add(new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Right));
numColumn.CellStyle = s;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTodView Question on Stackoverflow
Solution 1 - WpfWPF-itView Answer on Stackoverflow
Solution 2 - WpfRahbekView Answer on Stackoverflow
Solution 3 - WpfMichaelSView Answer on Stackoverflow
Solution 4 - WpfmattanjaView Answer on Stackoverflow
Solution 5 - WpfChristianView Answer on Stackoverflow