Apply WPF Style to certain data grid column - c#

I have this DataGrid
<DataGrid Name="OrderItemList" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Code" Binding="{Binding Code}" IsReadOnly="True" />
<DataGridTextColumn Header="Color" IsReadOnly="True" />
<DataGridTextColumn Header="Size" IsReadOnly="True" />
<DataGridTextColumn Header="Price" Binding="{Binding Price`}" IsReadOnly="True" />
<DataGridTextColumn Header="Qty" Binding="{Binding Qty}" />
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button>Remove</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="" Width="*" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
This is my style
<Style x:Key="TextColumn" TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="Background" Value="#F1F1F1" />
</Trigger>
</Style.Triggers>
<Setter Property="Padding" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text, Mode=TwoWay, UpdateSourceTrigger=Default}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}"
BorderThickness="0" IsReadOnly="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Column.IsReadOnly}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I apply this style to only DataGridTextColumn's cell?

You can simply set the CellStyle property on your DataGridTextColumn definition.
<DataGridTextColumn CellStyle="{StaticResource TextColumn}" ...

Related

Add Custom Rows at the top of DataGrid - WPF

I am new in WPF and I have a project that needs to have this output below
How can I do this? I just know a basic DataGrid code like this below:
<DataGrid AutoGenerateColumns="False" Name="myGrid" Margin="10">
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}, Path=Item.Header}"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
<DataGrid.Columns>
<DataGridTextColumn Header="Case Title" Binding="{Binding Path=Name}" Width="160" />
<DataGridComboBoxColumn Width="100" x:Name="dtgCbxColUnit" SelectedValueBinding="{Binding Unit, Mode=TwoWay}" DisplayMemberPath="{Binding Unit}" />
<DataGridTextColumn Header="Case 1" Binding="{Binding Path=Case1}" Width="80"/>
<DataGridTextColumn Header="Case 2" Binding="{Binding Path=Case2}" Width="80" />
<DataGridTextColumn Header="Case 3" Binding="{Binding Path=Case3}" Width="80" />
<DataGridTextColumn Header="Case 4" Binding="{Binding Path=Case4}" Width="80" />
<DataGridTextColumn Header="Case 5" Binding="{Binding Path=Case5}" Width="80" />
<DataGridTextColumn Header="Case 6" Binding="{Binding Path=Case6}" Width="80" />
</DataGrid.Columns>
</DataGrid>
How can I resolve this?
The DataGrid cell templating is done vertically (by columns) not horizontally (by rows). It means you can't make an exception for a few rows. If you want to have custom rows you have to apply it to all rows using DataGridTemplateColumn
<DataGrid.Columns>
<DataGridTemplateColumn Header="People">
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<!-- normal template -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock Text="{Binding A}" Background="Green"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RowType}" Value="0">
<Setter Property="Template">
<Setter.Value>
<!-- first extra template -->
<ControlTemplate>
<TextBlock Text="{Binding A}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RowType}" Value="1">
<Setter Property="Template">
<Setter.Value>
<!-- second extra template -->
<ControlTemplate>
<CheckBox Content="{Binding A}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
On the other hand DataGrid "styling" is done the opposite way using RowStyle. So you can write a trigger to customize one row completely with the cost of ignoring all cells (or columns) in that row:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding RowType}" Value="0">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Button Content="{Binding A}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
combined results:
Normally I would suggest to use your own implementation of the general ItemsControl if you think these customizations will grow in the future.
There is another workaround where you create a gap at the top of the grid and overlay stuff onto it using a Canvas or any control with ClipToBounds=False explained here

WPF MVVM DataGrid contents don't fit to row height change

I need to make my row height variable so that I can allow for some rows to add additional information. Setting the RowHeight value doesn't seem to make any difference. There is no value to set for height at the level of DataGridTextColumn as all the contents are bound (MVVM).
<Border Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Right" Margin="9" Width="auto" Visibility="{Binding LogVisibility}" VerticalAlignment="Stretch">
<DataGrid AutoGenerateColumns="False" VerticalContentAlignment="Center" ItemsSource="{Binding EventLog}" RowHeight="100" Background="White" CellStyle="{StaticResource cellStyle}" ColumnHeaderStyle="{StaticResource headerStyle}" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" SortMemberPath="CategoryDescription">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" MaxHeight="15" MaxWidth="15" VerticalAlignment="Center"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding CategoryDescription}" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--<DataGridTextColumn Header="Type" Binding="{Binding CategoryDescription}"></DataGridTextColumn>-->
<DataGridTextColumn Header="Date" Binding="{Binding Date}"/>
<DataGridTextColumn Header="Details" Binding="{Binding TypeDescription}" MaxWidth="400"/>
</DataGrid.Columns>
</DataGrid>
</Border>
Having set the value of RowHeight="{x:Static sys:Double.NaN}" doesn't change anything and instead I see truncated text as seen here:
If I set an arbitrary fixed height of RowHeight="100" (although not ideal), the rows content doesnt expand either, and show an ugly outline:
I added vertical scrolling, but I don't need horizontal scrolling, so I was hoping to have variable height so that longer text would wrap and fit, how can I achieve this?
Update (solution) - Thanks to Nomad developer
There was an offender style at the top of my XAML that applied to all the cells and was restricting them from expanding:
<Style TargetType="DataGridCell" x:Key="cellStyle" >
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="14"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" Margin="5,5,5,5" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="TextBlock.VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0" />
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Height" Value="35"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
I have removed this style now, and the final Datagrid is (using <DataGridTextColumn.ElementStyle>):
<DataGrid AutoGenerateColumns="False"
VerticalContentAlignment="Center"
ItemsSource="{Binding EventLog}"
MinRowHeight="30"
Background="White"
ColumnHeaderStyle="{StaticResource headerStyle}"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" SortMemberPath="CategoryDescription">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" MaxHeight="15" MaxWidth="15" VerticalAlignment="Center" Margin="5,0,5,0"/>
<TextBlock Text="{Binding CategoryDescription}" TextWrapping="Wrap" VerticalAlignment="Center" Margin="0,0,5,0"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Date" Binding="{Binding Date}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap"/>
<Setter Property="TextBlock.TextAlignment" Value="Justify" />
<Setter Property="TextBlock.VerticalAlignment" Value="Center"/>
<Setter Property="TextBlock.Margin" Value="5"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Details" Binding="{Binding TypeDescription}" MaxWidth="400">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap"/>
<Setter Property="TextBlock.TextAlignment" Value="Justify" />
<Setter Property="TextBlock.VerticalAlignment" Value="Center"/>
<Setter Property="TextBlock.Margin" Value="5"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Which helped me achieve this:
Yes that's possible if you add custom style with textblock wrapping for your DataGridTextColumn
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style>
</DataGridTextColumn.ElementStyle>
All you need is add TextWrapping as Wrap or WrapWithOverflow You can check out the difference here.
Also to make it work, you need to remove your RowHeight or you can change it from
RowHeight="100"
to
MinRowHeight="100"
It ensures that your rows height will at least be 100, and if text doesnt fit - can go longer in size for that specific row, but with original rowheight it cant change size and has fixed 100 height for all rows. Btw, 100 seems to be too high, may be 20-ish would be neat.
Give a try to this code, I also added TextAlignment to Justify just in case you might find it useful.
<Border Grid.Row="1"
Grid.Column="1"
Width="auto"
Margin="9"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
Visibility="{Binding LogVisibility}">
<DataGrid VerticalContentAlignment="Center"
AutoGenerateColumns="False"
Background="White"
CanUserAddRows="False"
CellStyle="{StaticResource cellStyle}"
ColumnHeaderStyle="{StaticResource headerStyle}"
ItemsSource="{Binding EventLog}"
MinRowHeight="20">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type"
SortMemberPath="CategoryDescription">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image MaxWidth="15"
MaxHeight="15"
VerticalAlignment="Center"
Source="{Binding Image}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding CategoryDescription}"
TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--<DataGridTextColumn Header="Type" Binding="{Binding CategoryDescription}"></DataGridTextColumn>-->
<DataGridTextColumn Binding="{Binding Date}"
Header="Date" />
<DataGridTextColumn MaxWidth="400"
Binding="{Binding TypeDescription}"
Header="Details">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
<Setter Property="TextBlock.TextAlignment" Value="Justify" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Border>

WPF DataGridCell Margin

I have the following data grid:
<DataGrid Name="PropertiesDataGrid"
ItemsSource="{Binding PropertiesDataView, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedProperty, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False"
CanUserAddRows="False"
MaxHeight="200">
<i:Interaction.Behaviors>
<helper:ScrollIntoViewBehavior/>
</i:Interaction.Behaviors>
<DataGrid.Columns>
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="Delete"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Image Source="../Resources/red_x.ico"
Height="15" />
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="ID"
Width="50"
Binding="{Binding ID}"
ElementStyle="{StaticResource CenterTextCellStyle}"
IsReadOnly="True" />
<DataGridTextColumn Header="PropertyName"
Width="*"
Binding="{Binding PropertyName}"
ElementStyle="{StaticResource LeftTextCellStyle}" />
<DataGridTextColumn Header="PropertyValue"
Width="300"
Binding="{Binding PropertyValue}"
ElementStyle="{StaticResource LeftTextCellStyle}" />
</DataGrid.Columns>
</DataGrid>
Applied to this data grid is the following style:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Height" Value="22" />
<Setter Property="Margin" Value="5,0,0,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This style adds 5 pixels of spacing to the left of the cell contents and centers the text vertically.
I would like to set the margin of just the first column's cells (<DataGridTemplateColumn Header="">) to 0. How can I set this in the DataTemplate. I know the Margin has to be set on DataGridCell (found by using Snoops) but do not know how to implement in the <DataGridTemplateColumn.CellTemplate>
Cascade the style:
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="Margin" Value="0" />
</Style>
</DataGridTemplateColumn.CellStyle>

WPF DataGrid: How do I get all buttons in a DataGridTemplateColumn to have the same image?

Hello, I am having some issues styling the DataGrid in WPF. I have a column which consists of an image button (button where content is an image) that represents opening the file in excel. The image is only appearing for the first created row leaving the rest of the buttons in the column without an image.
The question: How can I get every button in the "Open" column to have the Excel image as it's content?
Button style:
<Style x:Key="btnOpenJr" TargetType="Button">
<Setter Property="Width" Value="20"/>
<Setter Property="Height" Value="20"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Content">
<Setter.Value>
<Image Height="20" Source="/BTLogFrontEnd;component/Resources/open_excel.ico"/>
</Setter.Value>
</Setter>
</Style>
DataGridCell style:
<Style x:Key="cellStyle" TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="DeepSkyBlue">
<ContentPresenter
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="Lime">
<ContentPresenter
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
DataGrid definition:
<DataGrid
Name="grdData"
CellStyle="{StaticResource cellStyle}"
Margin="10"
FontFamily="Verdana"
Foreground="MidnightBlue"
Background="MidnightBlue"
BorderBrush="Transparent"
AutoGenerateColumns="False"
RowHeight="22"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="True"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="True"
RowHeaderWidth="5"
ItemsSource="{Binding GridData}"
SelectionUnit="CellOrRowHeader"
Width="550"
ColumnHeaderStyle="{StaticResource gridHeaderStyle}"
SelectionMode="Extended">
<DataGrid.Columns>
<DataGridTemplateColumn
Width="40"
Header="Open">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Style="{StaticResource btnOpenJr}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridCheckBoxColumn
Width="65"
Header="Approved">
</DataGridCheckBoxColumn>
<DataGridTextColumn
Width="40"
Binding="{Binding Number}"
Header="JR #"/>
<DataGridTextColumn
Width="55"
Binding="{Binding Process}"
Header="Process"/>
<DataGridTextColumn
Width="55"
Binding="{Binding Wafer}"
Header="Wafer"/>
<DataGridTextColumn
Width="335"
Binding="{Binding Description}"
Header="Description"/>
</DataGrid.Columns>
</DataGrid>
Any help will be greatly appreciated.
Regards,
Kyle
I found a solution:
Remove the "btnOpenJr" button style out from the app.xaml file and use an inline style for that column in the DataGrid definition.
The new DataGrid definition becomes:
<DataGrid
Name="grdData"
CellStyle="{StaticResource cellStyle}"
Margin="10"
FontFamily="Verdana"
Foreground="MidnightBlue"
Background="MidnightBlue"
BorderBrush="Transparent"
AutoGenerateColumns="False"
RowHeight="22"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="True"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="True"
RowHeaderWidth="5"
ItemsSource="{Binding GridData}"
SelectionUnit="CellOrRowHeader"
Width="550"
ColumnHeaderStyle="{StaticResource gridHeaderStyle}"
SelectionMode="Extended">
<DataGrid.Columns>
<DataGridTemplateColumn
Width="40"
Header="Open">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Width="20"
Height="20"
HorizontalContentAlignment="Center">
<Image
Height="20"
Source="/BTLogFrontEnd;component/Resources/open_excel.ico"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridCheckBoxColumn
Width="65"
Header="Approved">
</DataGridCheckBoxColumn>
<DataGridTextColumn
Width="40"
Binding="{Binding Number}"
Header="JR #"/>
<DataGridTextColumn
Width="55"
Binding="{Binding Process}"
Header="Process"/>
<DataGridTextColumn
Width="55"
Binding="{Binding Wafer}"
Header="Wafer"/>
<DataGridTextColumn
Width="335"
Binding="{Binding Description}"
Header="Description"/>
</DataGrid.Columns>
</DataGrid>

why Cell Header and Cell contents are not aligned in datagrid?

I have this xaml code:
<DataGridTextColumn Header="number" Binding="{Binding Path=Number, Mode=OneWay}" Width="70" CanUserResize="False" >
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Status" Binding="{Binding Path=ProcessingState}" Width="100">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
but when it shows on screen, it generate this view:
As can be seen, the cells are not aligned with header. How can I make them aligned?
If you just want to centre the text in the cells, then you could use a DataGridTemplateColumn like this:
<DataGrid ItemsSource="{Binding SalesPeriods}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="number" Width="70" CanUserResize="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Number, Mode=OneWay}"
HorizontalAlignment="Center" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Status" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ProcessingState, Mode=OneWay}"
HorizontalAlignment="Center" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
If you prefer to use a DataGridTextColumn, then you could still achieve this goal using the ElementStyle property:
<DataGridTextColumn Header="number" Binding="{Binding Path=Year, Mode=OneWay}"
Width="70" CanUserResize="False" >
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

Categories