Datagrid Column Header Templating - wpf

I want to template some headercolumns in a pretty simple way, but I don't get the results I am looking for. I want the Border to fill the whole header, not just the textbox inside. Right now I am still having the default gray behind my own controls.
<DataGrid x:Name="grdItems"
Grid.Row="0"
CanUserAddRows="False"
CanUserDeleteRows="False"
ItemsSource="{Binding Path=Items}"
CanUserSortColumns="False" AutoGenerateColumns="False" CanUserResizeColumns="False">
<DataGrid.Columns>
<DataGridComboBoxColumn ItemsSource="{Binding Source={StaticResource GetSignalTypeValues}}" Width="auto" SelectedValueBinding="{Binding SignalType}" >
<DataGridComboBoxColumn.HeaderTemplate>
<DataTemplate>
<Border Background="Orange" >
<TextBlock Text="Signal Type" />
</Border>
</DataTemplate>
</DataGridComboBoxColumn.HeaderTemplate>
</DataGridComboBoxColumn>
<DataGridTextColumn Width="auto" Binding="{Binding AmplitudeMax}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<Border Background="Violet">
<StackPanel>
<TextBlock Text="Amplitude" HorizontalAlignment="Center" />
<TextBlock Text="-maximum-" HorizontalAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>

If you are only after background color of column header you can utilize this:
<DataGridComboBoxColumn Width="auto" SelectedValueBinding="{Binding SignalType}" >
<DataGridComboBoxColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="Orange"/>
</Style>
</DataGridComboBoxColumn.HeaderStyle>

Related

WPF DataTemplate and columns definition

I need to improve the render of my grid. I have a template:
<DataTemplate x:Key="ubitTemplateService" DataType="{x:Type data:uBit}">
<Grid HorizontalAlignment="Stretch" x:Name="grdBit">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="MAMC" />
<ColumnDefinition Width="Auto" SharedSizeGroup="ID" />
<ColumnDefinition Width="Auto" SharedSizeGroup="lblVIS" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding FIELD_Mac, Mode=OneWay}" Style="{StaticResource labelStyle1}" />
<TextBlock Grid.Column="1" Text="{Binding Name}" Style="{StaticResource txtBlockStyle2}" />
<Label Grid.Column="1" Content="{Binding Show.Caption}" Style="{StaticResource labelStyle4}" />
</Grid>
</DataTemplate>
Basically for each record of my collection, a grid is rendered but as I have 300 or more record, the whole render takes about 2-3 seconds (each template was rendered into a Listbox)
I would want to change the layout and use a datagrid as follows:
<DataGrid x:Name="gridDati" BorderBrush="#abadb3" CanUserSortColumns="true" Margin="8,7,5,8">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name" CellTemplateSelector="{StaticResource DataTemplateSelector}" />
</DataGrid.Columns>
</DataGrid>
and I would want to use a datatemplate in order to render the columns, which may changes base on my datatype. The template selector is:
<local:DataconfigTemplateSelector ubitTemplateAv="{StaticResource ubitTemplateAv}" x:Key="DataTemplateSelector" />
The problem is that I want to put into my datatemplate the definition of DataGrid columns, for example a DataGridTextColumn:
<DataTemplate x:Key="ubitTemplateAv">
<StackPanel>
...
</StackPanel>
</DataTemplate>
How can I put into my datatemplate the columns definition like?
<DataGridTextColumn Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Header="Nome" Foreground="Black" IsReadOnly="True" x:Name="colName">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Padding" Value="4,7,4,6" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding SurName, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Header="SurName" Foreground="Black" IsReadOnly="True" x:Name="colSurName">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Padding" Value="4,7,4,6" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
the key is to use DataGridTemplateColumn instead of DataGridTextColumn.
Then you can do this:
<DataGridTemplateColumn
Width="80">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Foo}" Padding="4,7,4,6"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

column line are not sync in datagrid in wpf

I have added one datagrid control to show employee details and binded with ObservableCollection.
I have grouped the data based on country.
but now problem is that, column header's vertical line (line which separate out the columns) not sync with the column data.(the lines in the data part of the grid, is moved slightly right with respect to the header lines.)
if I remove group header then column header vertical line sync with columns data.
Is there any property to sync the line with entire column?
below is the xaml code
<Grid>
<Custom:DataGrid x:Name="dgData" CanUserAddRows="False" AutoGenerateColumns="False" HeadersVisibility="Column"
CanUserDeleteRows="False" ItemsSource="{Binding}">
<Custom:DataGrid.GroupStyle>
<GroupStyle >
<GroupStyle.HeaderTemplate>
<DataTemplate>
<DockPanel Background="LightBlue">
<TextBlock Text="{Binding Name}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>
</DockPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</Custom:DataGrid.GroupStyle>
<Custom:DataGrid.Columns>
<Custom:DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<Custom:DataGridTextColumn Header="Contact" Binding="{Binding Contact}"/>
<Custom:DataGridTextColumn Header="Email ID" Binding="{Binding EmailID}"/>
<Custom:DataGridTextColumn Header="Country" Binding="{Binding Country}"/>
</Custom:DataGrid.Columns>
</Custom:DataGrid>
</Grid>
below is code behind file
public Window1()
{
InitializeComponent();
ObservableCollection<Employee> empData = new ObservableCollection<Employee>
{
new Employee{Name="Diptimaya Patra", Contact="0000",
EmailID="diptimaya.patra#some.com", Country="India"},
new Employee{Name="Dhananjay Kumar", Contact="00020",
EmailID="dhananjay.kumar#some.com", Country="India"},
new Employee{Name="David Paul", Contact="1230",
EmailID="david.paul#some.com", Country="India"},
new Employee{Name="Christina Joy", Contact="1980",
EmailID="christina.joy#some.com", Country="UK"},
new Employee{Name="Hiro Nakamura", Contact="0000",
EmailID="hiro.nakamura#some.com", Country="Japan"},
new Employee{Name="Angela Patrelli", Contact="0000",
EmailID="angela.patrelli#some.com", Country="Japan"},
new Employee{Name="Zoran White", Contact="0000",
EmailID="diptimaya.patra#some.com", Country="Scotland"},
};
ListCollectionView collection = new ListCollectionView(empData);
collection.GroupDescriptions.Add(new PropertyGroupDescription("Country"));
dgData.ItemsSource = collection;
}
Yes you have to set GroupStyle.ContainerStyle Property too.
I have modified your code with following.
<DataGrid x:Name="dgData" CanUserAddRows="False" AutoGenerateColumns="False" HeadersVisibility="Column"
CanUserDeleteRows="False" ItemsSource="{Binding}">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<DockPanel Background="LightBlue">
<TextBlock Text="{Binding Name}" Foreground="Blue" Margin="30,0,0,0" Width="100" DockPanel.Dock="Top"/>
<ItemsPresenter />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Contact" Binding="{Binding Contact}"/>
<DataGridTextColumn Header="Email ID" Binding="{Binding EmailID}"/>
<DataGridTextColumn Header="Country" Binding="{Binding Country}"/>
</DataGrid.Columns>
</DataGrid>
Or
you can use like this too.
<StackPanel Background="LightBlue" Orientation="Vertical">
<TextBlock Text="{Binding Name}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>
<ItemsPresenter />
</StackPanel>

Unable to see vertical scroll bar in datagrid when placed inside grid in WPF

From last 2 day I am stuck in a small problem which I don't know why I was not able to solve it. I had did lots off goggling and implemented various suggestion provided by stack overflow to solve out the problem but finally I am getting tired off by unsuccessful implementation.
My problem is that I want a scroll able data grid which could be placed inside a Grid control or DockPanel(As I had tried with both). Below is code which I am using.
<Grid IsEnabled="{Binding IsCalcVarGridPartEnable}">
<Grid.Resources>
<BooleanToVisibilityConverter x:Key="boolToVisiblityConverter" />
<sys.converters:BoolToVisibleHiddenConvertor x:Key="boolToVisibleHiddenConvertor"/>
<FrameworkElement x:Key="ProxyElement"
DataContext="{Binding}"/>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Border Style="{StaticResource SeperatorStyle}" Grid.Row="0">
<TextBlock Style="{StaticResource BannerTextStyle}" Text="Calculation Variable" />
</Border>
<Border Style="{StaticResource SeperatorStyle}" Grid.Row="2">
<Button Content="Edit" HorizontalAlignment="Right" Margin="10,5" Command="{Binding EditCalcVarCmd}" />
</Border>
<ContentControl Visibility="Collapsed"
Content="{StaticResource ProxyElement}"/>
<DataGrid AutoGenerateColumns="False"
Name="dataGridCalcVar"
VerticalAlignment="Top"
HorizontalAlignment="Left"
IsReadOnly="True"
SelectionMode="Single"
SelectionUnit="FullRow"
ItemsSource="{Binding CalcVarCollection}"
SelectedItem="{Binding SelectedCalcVar}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick" >
<i:InvokeCommandAction Command="{Binding CalcVarDoubleClickedCmd}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.ColumnHeaderStyle>
<StaticResourceExtension ResourceKey="DataGridColumnHeaderStyle" />
</DataGrid.ColumnHeaderStyle>
<DataGrid.CellStyle>
<StaticResourceExtension ResourceKey="DataGridCellStyle" />
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Type Description" MinWidth="150" MaxWidth="200" Binding="{Binding CalcTypName}" />
<DataGridTextColumn Header="Variable Description" MinWidth="150" MaxWidth="200" Binding="{Binding CalcVarName}" />
<DataGridTextColumn Header="Major Description" MinWidth="150" MaxWidth="200" Binding="{Binding MjAcctTypDesc}"
Visibility="{Binding DataContext.IsMjMiAcctTypVisible, Source={StaticResource ProxyElement},
Converter={StaticResource boolToVisibleHiddenConvertor}}" />
<DataGridTextColumn Header="Minor Description" MinWidth="150" MaxWidth="200" Binding="{Binding MiAcctTypDesc}"
Visibility="{Binding DataContext.IsMjMiAcctTypVisible, Source={StaticResource ProxyElement},
Converter={StaticResource boolToVisibleHiddenConvertor}}" />
<DataGridTextColumn Header="DNA Value" MinWidth="50" MaxWidth="200" Binding="{Binding CalcVarValueName}" />
<DataGridTextColumn Header="Critical Value" MinWidth="50" MaxWidth="200" Binding="{Binding CriticalValueName}" />
<DataGridTextColumn Header="Note" MinWidth="150" MaxWidth="200" Binding="{Binding Note}" />
</DataGrid.Columns>
</DataGrid>
<sysclient:PartStatusView Grid.RowSpan="5" Grid.ColumnSpan="7"
Style="{DynamicResource PartStatusViewDefaultStyle}" IsTabStop="False"/>
</Grid>
Important: I am able to get scroll bar only when I set max height of Datagrid control but I don't want to set max-height property of either row or datagrid control. I want that when I resize window or whatever space is available datagrid is set into that space and when we query the data then if data data is greater than available space then data grid brings vertical scroll bar.
Please help me!!!!!
I hope I am able to explain my problem. :-) :-)
Thanks,
From what I can see there are two attributes which can help you here
add Grid.Row="1" to your data grid
remove VerticalAlignment="Top" from the same which actually prevent it to take height from the container
eg
<DataGrid AutoGenerateColumns="False"
Name="dataGridCalcVar"
Grid.Row="1"
HorizontalAlignment="Left"
IsReadOnly="True"
SelectionMode="Single"
SelectionUnit="FullRow"
ItemsSource="{Binding CalcVarCollection}"
SelectedItem="{Binding SelectedCalcVar}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
I am assuming that you want to place grid in the middle row which takes up the remaining space.

Dynamically set a property in an Item Template

I set an image path of an Image in a StackPanel used in a GroupItem using the following resource (which as is works fine):
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Name="expander" IsExpanded="True" >
<Expander.Header>
<StackPanel Orientation="Horizontal">
<Image Source="pack://application:,,,/Resources/History.ico" Margin="2,0"
Width="18" Height="18" ></Image>
<TextBlock Text="{Binding Name}" Padding="2,0"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Which is used in this DataGrid:
<DataGrid Name="JobHistory" CanUserAddRows="False" AutoGenerateColumns="False" ColumnWidth="*"
CanUserDeleteRows="False" ItemsSource="{Binding}" Grid.Row="2"
Grid.ColumnSpan="5" CanUserResizeRows="False"
Grid.RowSpan="2" IsTextSearchEnabled="True" VerticalScrollBarVisibility="Visible" >
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Status" Width="Auto" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ResultImagePath}" Height="18" Width="18"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Job description" Binding="{Binding JobDescription}"/>
</DataGrid.Columns>
</DataGrid>
The DataView is grouped via this code:
ListCollectionView collection = new ListCollectionView(JobData);
collection.GroupDescriptions.Add(new PropertyGroupDescription("Name"));
JobHistory.ItemsSource = collection;
My Question: How can I dynamically set the image Source in the StackPanel?
<StackPanel Orientation="Horizontal">
<Image Source="pack://application:,,,/Resources/History.ico" Margin="2,0"
Width="18" Height="18" ></Image>
<TextBlock Text="{Binding Name}" Padding="2,0"/>
</StackPanel>
Edit 1:
Using:
<UserControl.Resources>
<Image x:Key="image" Source="pack://application:,,,/Resources/History.ico" Height="18" Width="18" Margin="2,0"/>
</UserControl.Resources>
<StackPanel Orientation="Horizontal">
<ContentControl Content="{StaticResource ResourceKey=image}"/>
Width="18" Height="18" ></Image>
<TextBlock Text="{Binding Name}" Padding="2,0"/>
</StackPanel>
as user2760623 suggested works.
My Problem however remains. At any given time I have multiple rows grouped by "Name". There can also be several different Groups. Depending on the Jobs current Status, I would like to Change the Image in the GroupItem Header. So how do I figure out which header is the "right" Header, and how do I manipulate exactly that one single Header?
Put the image source as a dynamic resource, and then you can change it. Just do the following:
Define the namespace - xmlns:clr="clr-namespace:System;assembly=mscorlib".
Add as resource - <clr:String x:Key="imageSource" >the path...</clr:String>.
And the image itself - <Image Source="{DynamicResource ResourceKey=imageSource}".
And when you want to change it - this.Resources["imageSource"] = "another path...".
You can also do the same concept just put the whole image as a resource (instead of just the image path), than you don't need to add the namespace (number 1 above). And put it as a Content of a ContentControl -
<ContentControl Content="{StaticResource ResourceKey=image}"/>.

Padding on a Datagrid Row

I have a WPF Datagrid with a Text Column, two Template Columns, and two Checkbox Columns.
The template columns are center aligned vertically (equal padding top and bottom), the text column has a little padding on top, but a lot on the bottom, and the checkboxes only have about 1 pixel padding on top.
I'd like to center vertical align all of them, but I don't want to have to make a template column to hold the check boxes and text box.
What's the proper way to do this?
Edit: XAML
<DataGrid AutoGenerateColumns="False" Name="dgROList" ItemsSource="{Binding ElementName=MainWindow, Path=cROInfo}" CanUserDeleteRows="True" CanUserReorderColumns="False" GridLinesVisibility="Horizontal" Margin="0,0,0,0" Grid.ColumnSpan="2" AlternatingRowBackground="#FFFFE776">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Name="mnuDelete" Header="Delete" />
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn Header="RO Number" Width="Auto" Binding="{Binding RONum}" />
<DataGridTemplateColumn x:Name="roDetails" Header="RO Details" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl Name="LineDetails" ItemsSource="{Binding LineInfo}" Width="Auto" Grid.IsSharedSizeScope="True">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ItemsPresenter />
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" SharedSizeGroup="DetailCol"/>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="150*"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding Line}" Grid.Column="0" />
<Label Content="{Binding Status}" Grid.Column="1" />
<Label Content="{Binding AmountPaid}" Grid.Column="2" />
<Label Content="{Binding SDate}" Grid.Column="3" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="roRI" Header="RI" Width="Auto" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding RI}" ToolTipService.ShowDuration="60000" ></Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridCheckBoxColumn Header="Paid" Width="40" Binding="{Binding Paid}" />
<DataGridCheckBoxColumn Header="Adj" Width="30" Binding="{Binding Adjustment}" />
</DataGrid.Columns>
</DataGrid>
Edit 2: Actually, I don't even need to vertically align them. Just adding a little padding to the top so it'll line up with the top of the Template Columns.
have you tried this:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>

Resources