WPF DataTemplate and columns definition - wpf

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>

Related

dynamically generate tool-tip on hover on any cell of a grid in WPF

I have not worked on Silverlight at all and have been stuck in one of the requirement for some application which runs on Silverlight.
Requirement:
I want to display Tool-tip on my grid which have below Columns and on hover over ID column, I want to display tool-tip for each row separately based on the ID for that row.
This is how Grid Looks:
I have the below code for Data-Grid:
<UserControl xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
x:Class="MYAPP.View.Pages.MyPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:src="clr-namespace:MYAPP.View"
xmlns:pag="clr-namespace:MYAPP.View.Pages"
xmlns:ctl="clr-namespace:MYAPP.Controls;assembly=MYAPP.Controls"
xmlns:log="clr-namespace:MYAPP.Logic.WCF.Services;assembly=MYAPP.Logic"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
>
<Grid Name="grdMain">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ctl:FieldHelp x:Name="grdMyGrid" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="40,10"
ItemsSource="{Binding PendingRequests, Mode=TwoWay}"
DoubleClick="grdMyGrid_DoubleClick"
CurrentCellChanged="grdChildren_CurrentCellChanged"
Visibility="{Binding PendingRequestsDetail, ConverterParameter=false, Converter={StaticResource VisibilityConverter}}"
AutoGenerateColumns="False">
<ctl:FieldHelp.Columns>
<data:DataGridTextColumn Binding="{Binding ID, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding Description, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding Date, Mode=TwoWay, Converter={StaticResource ShortDateStringConverter}}" IsReadOnly="True"/>
<data:DataGridCheckBoxColumn Binding="{Binding Process, Mode=TwoWay}" IsReadOnly="False" IsThreeState="False"/>
</ctl:FieldHelp.Columns>
</ctl:FieldHelp>
</Grid>
</UserControl>
I have no Idea on how to work on the requirement."
Searching on net didn't gave me proper solution to which I end up getting the same Name in tool-tip as that of row's cell.
Only Get Name in tool-tip
<ctl:FieldHelp x:Name="grdMyGrid" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="40,10"
ItemsSource="{Binding PendingRequests, Mode=TwoWay}"
DoubleClick="grdMyGrid_DoubleClick"
CurrentCellChanged="grdChildren_CurrentCellChanged"
Visibility="{Binding PendingRequestsDetail, ConverterParameter=false, Converter={StaticResource VisibilityConverter}}"
AutoGenerateColumns="False">
<ctl:FieldHelp.Columns>
<data:DataGridTextColumn Binding="{Binding ID, Mode=TwoWay}" IsReadOnly="True" >
<data:DataGridTextColumn.CellStyle>
<Style TargetType="data:DataGridCell" >
<Setter Property="ToolTipService.ToolTip" Value="{Binding Name}" />
</Setter>
</Style>
</data:DataGridTextColumn.CellStyle>
</data:DataGridTextColumn>
<data:DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding RelativeName, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding ID, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding Description, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding Date, Mode=TwoWay, Converter={StaticResource ShortDateStringConverter}}" IsReadOnly="True"/>
<data:DataGridCheckBoxColumn Binding="{Binding Process, Mode=TwoWay}" IsReadOnly="False" IsThreeState="False"/>
</ctl:FieldHelp.Columns>
</ctl:FieldHelp>
</Grid>
</UserControl>
But I want to dynamically bind the tool-tip which shows data based on the record ID-on which I have hovered.
Tool-tip should be seen like this
I would add a style that sets up your Tooltip
<ctl:FieldHelp...>
<ctl:FieldHelp.Resources>
<Style TargetType="DataGridCell">
<Setter Property="ToolTip" Value="{Binding ID, StringFormat=Tooltip for ID:{0}}" />
</Style>
</ctl:FieldHelp.Resources>
<!-- The rest of your column etc -->
However, if the FieldHelp control (ctl:FieldHelp) isn't a sub-classed DataGrid then I don't think this solution will work for you.

Bind to property in a relative source sends me up to the mainwindow + Catel

Have the following xaml code
<catel:UserControl x:Class="SICUAP.Views.CatProducto_CategoriasView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:Views="clr-namespace:SICUAP.Views">
<!-- Resources -->
<UserControl.Resources>
</UserControl.Resources>
<!-- Content -->
<catel:StackGrid>
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>
<Views:cmdGlobalesBDView></Views:cmdGlobalesBDView>
<Label Content="Catalogo de Categorias de Producto" Style="{StaticResource estiloTituloControl}">
</Label>
<DataGrid Margin="0 10 0 0" MaxHeight="200" ItemsSource="{Binding Producto_Categorias}" SelectedItem="{Binding SelectedProducto_Categoria}" AutoGenerateColumns="False"
ScrollViewer.VerticalScrollBarVisibility="Auto" CanUserAddRows="False" CanUserResizeColumns="False" AlternatingRowBackground="#D2EDF7">
<DataGrid.Columns>
<DataGridTemplateColumn Header="CLAVE" MinWidth="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding ID_CATEGORIA}"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="NOMBRE" MinWidth="200">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding NOMBRE}"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="DESCRIPCION" MinWidth="300">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding DESCR}" HorizontalAlignment="Stretch"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
<Views:dataProducto_CategoriasView DataContext="{Binding SelectedProducto_Categoria}" Visibility="{Binding RelativeSource= {RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.VistaDetalleEsVisible, Converter={StaticResource booleanToVisibilityConverter}}" />
</catel:StackGrid>
</catel:UserControl>
When i try to bind the Visibility property of the internal view
<Views:dataProducto_CategoriasView DataContext="{Binding SelectedProducto_Categoria}" Visibility="{Binding RelativeSource= {RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.VistaDetalleEsVisible, Converter={StaticResource booleanToVisibilityConverter}}" />
to the parent it sends me all the way up to the datacontext of the main window.
The parent is loaded in a contentControl inside the main window.
Why i cant bind to the datacontext of the parent user control?
It's exactly the same question as this one.
Read the docs, specifically the article UserControl - Under the hood.

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>

Datagrid Column Header Templating

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>

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