WPF Custom datagrid column header - c#

I need to create a Custom dataGrid DataGridTextColumn like the sketch below:
The Red rectangles are TextBox and are used to search within the column.
so far i have implemented a datagrid like this (simplify Version):
<DataGrid x:Name="CompassLogDataGrid"
Grid.Row="1"
Style="{DynamicResource ResourceKey=DataGridStyle}"
IsTextSearchEnabled="True">
<DataGrid.Columns>
<DataGridTextColumn CellStyle="{StaticResource IdCell}"
x:Name="ID"
Header="ID"
Foreground="Black"
Binding="{Binding ID}"
DisplayIndex="0" />
<DataGridTextColumn x:Name="DateGTC"
Header="Date"
Binding="{Binding DateString}"
CellStyle="{StaticResource DateGTCCell}" />
</DataGrid.Columns
</DataGrid
I have no idea how to create those textBoxes. Any clue would be appreciate it

DataGridTemplateColumn is what you are looking for. You can customize the template as per your need -
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox BorderBrush="Red" BorderThickness="3" Margin="5"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
With sample ItemsSource it gives this look -
EDIT
In case you want to customize the header, you need to provide HeaderTemplate for your column like this -
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}"
Header="{Binding HeaderName}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Content, RelativeSource=
{RelativeSource Mode=TemplatedParent}}"
Margin="5"/>
<TextBox BorderBrush="Red" BorderThickness="3"
Width="50" Margin="5"/>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Here's the look -

Related

WPF DataGrid repeat Headers in all rows

My requirement is to display headers of DataGrid in following format instead of normal grid.
My code for normal DataGrid as follows:
<DataGrid Margin="7.208,8,7.888,8" Grid.Row="2" AutoGenerateColumns="False" Name="gridOrder" BorderBrush="#FFB38807" Background="#FFEDEDEC" HorizontalGridLinesBrush="#FFB38807" VerticalGridLinesBrush="#FFB38807" SelectionChanged="gridOrder_SelectionChanged" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Order ID" Binding="{Binding orderid}" />
<DataGridTextColumn Header=" Order Time" Binding="{Binding orderTime}" />
<DataGridTextColumn Header="Order Status" Binding="{Binding orderStatus}" />
</DataGrid.Columns>
</DataGrid>
Can any one help me out for this kind of requirement.
<DataGrid AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="OrderId : "/>
<TextBlock Text="{Binding OrderId}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="OrderTime : "/>
<TextBlock Text="{Binding OrderTime}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="OrderStatus : "/>
<TextBlock Text="{Binding OrderStatus}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>

MVVM WPF properties

In my WPF project a DataGrid is bound to a collection. When DataGrid row selection changes the corresponding TextBox, should get updated. The DataGrid selected item is bound to a property
SelectedItem="{Binding CardType.SelectedCard}"
and corresponding Text box is bound
Text="{Binding CardType.SelectedCard.LimitBalance}"
so when a selected item is changed, my text box will get updated.
DataGrid
<DataGrid
x:Name="dtGridSearch"
Margin="0,0,8,0"
AutoGenerateColumns="False"
GridLinesVisibility="None"
SelectionMode="Single"
CanUserAddRows="False"
BorderThickness="0"
RowHeaderWidth="0"
RowStyle="{StaticResource TCAS_RowStyle}"
ItemsSource="{Binding CardType.Cards}"
SelectedItem="{Binding CardType.SelectedCard}"
SelectionChanged="dtGridSearchSelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn x:Name="CardCode" Binding="{Binding CardId}" HeaderStyle="{StaticResource DataGridColumnHeaderStyle}" IsReadOnly="True" Width="150" CanUserResize="False" >
<DataGridTextColumn.Header>
<TextBlock x:Name="tbCardCode" Text=""/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn x:Name="CardName" Binding="{Binding CardDescription}" HeaderStyle="{StaticResource DataGridColumnHeaderStyle}" IsReadOnly="True" Width="250" CanUserResize="False" >
<DataGridTextColumn.Header>
<TextBlock x:Name="tbCardName" Text="" HorizontalAlignment="Center"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn x:Name="ProductCode" Binding="{Binding ProductTypeCode}" HeaderStyle="{StaticResource DataGridColumnHeaderStyle}" IsReadOnly="True" Width="150" CanUserResize="False" >
<DataGridTextColumn.Header>
<TextBlock x:Name="tbProductCode" Text=""/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn x:Name="Limitbalance" Binding="{Binding LimitBalance}" HeaderStyle="{StaticResource DataGridColumnHeaderStyle}" IsReadOnly="True" Width="100*" CanUserResize="False" >
<DataGridTextColumn.Header>
<TextBlock x:Name="tbLimitbalance" Text="" HorizontalAlignment="Center"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
TextBox
<TextBox
x:Name="txtLimitbalance"
Grid.Row="3"
Grid.Column="1"
Margin="16,0,0,0"
Style="{StaticResource TMS_TextBox_Base1}"
Text="{Binding CardType.SelectedCard.LimitBalance, Mode=TwoWay}"
MaxLength="45"
Height="24"
Width="210"
TabIndex="4"
PreviewKeyDown="txtLimitbalancePreviewKeyDown"/>
<CheckBox
x:Name="chkused"
Grid.Row="3"
Grid.Column="2"
Margin="16,4,0,8"
Content="{Binding Resources.NPUsed}"
IsChecked="{Binding CardType.SelectedCard.ActiveStatus, Mode=TwoWay}"
TabIndex="5"/>
User update the text box to a different value from original value , so one property of row1 is updated ,now user selected the different row i.e rowenter code here2 from datagrid. again user selected the row1 so it is dispalying updated value not original value. I want to display original value only.

Combobox in a cell of DataGrid

I have a database with Table name “tblProducts” with columns header “ProductCode, Descriptions, UnitPirce, Quantity, TotalPrice”
I have a DataGrid in my WPF form, and manually create the column headers as below:
<DataGrid x:Name="dataGridOrderedProducts" Margin="10,10,10,0" Grid.Row="3" Grid.ColumnSpan="4" VerticalAlignment="Center" Height="180" BorderThickness="1">
<DataGrid.Columns>
<DataGridTextColumn Header="Product Code" MinWidth="120" FontSize="11"/>
<DataGridTextColumn Header="Descriptions" MinWidth="200" FontSize="11"/>
<DataGridTextColumn Header="Unit Price" MinWidth="100" FontSize="11"/>
<DataGridTextColumn Header="Quantity" MinWidth="100" FontSize="11"/>
<DataGridTextColumn Header="Total Price" MinWidth="100" FontSize="11"/>
</DataGrid.Columns>
</DataGrid>
I want to have a ComboBox in a cell under “Product Code” columns so that users can select a product and query all the related data from that ProductCode.
How can I do that?
You can do this in two- ways,
(i).By using DataGridComboboxColom
<DataGridComboBoxColumn Width="100" x:Name="cmbProduct" SelectedValueBinding="{Binding Code, Mode=TwoWay}" DisplayMemberPath="{Binding Code}"></DataGridComboBoxColumn>
</DataGrid.Columns>
(ii)By using DataTemplate
<DataGridTemplateColumn Header="ProductCode">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Code}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Codes}"></ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

WPF Dataset DataGrid Foreign Key Binding

I have two tables in a dataset:
Schedules
-------------
id INT
schedule_date DATETIME
service_id INT FOREIGN KEY REFERENCES services(id)
Services
-------------
id INT
name VARCHAR
I can easily bind a DataGridComboBoxColumn and get the result I want in the following way:
<DataGridComboBoxColumn Header="Service"
ItemsSource="{Binding Source={StaticResource schedulesDataSet}, Path=services}"
DisplayMemberPath="name"
SelectedValueBinding="{Binding Path=service_id}"
SelectedValuePath="id" />
But how do I do it with a DataGridTemplateColumn? I want to do this:
<DataGridTemplateColumn Header="Service" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=services.name}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
But as I am using a Dataset and not Entity Framework, I guess that's why it doesn't work.
What's the right way to do it?
EDIT:
Complete DataGrid code:
<Grid DataContext="{Binding Source={StaticResource schedulesViewSource}}">
<DataGrid Margin="0,10,0,0" Grid.Row="1" ItemsSource="{Binding}" AutoGenerateColumns="False" CanUserResizeRows="False" Name="schedulesDataGrid">
<DataGrid.Columns>
<DataGridTextColumn Header="Date" Binding="{Binding Path=schedule_date,StringFormat=dd-MMM-yy,ConverterCulture=da-DK}" Width="*" />
<DataGridTemplateColumn Header="Service" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=services.name}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridComboBoxColumn Header="Status" Width="*" x:Name="scheduleStatusColumn" ItemsSource="{StaticResource ScheduleStatuses}" />
<DataGridTextColumn Header="Source" Binding="{Binding Path=done_by}" Width="*" />
</DataGrid.Columns>
</DataGrid>
</Grid>
Set the ItemsSource for your DataGrid
<DataGrid Margin="0,10,0,0" Grid.Row="1" ItemsSource="{Binding schedulesViewSource, Mode=OneWay}" AutoGenerateColumns="False" CanUserResizeRows="False" Name="schedulesDataGrid">

problem with wpf datagrid selection + expander

I have an expander containing a datagrid with a rowdetailstemplate.
When I click on a datagrid row to see the row details template, the expander closes!
Anyone know why and how to fix this?
Update
Turns out that something else is happening:
The expanders are all contained in a TabItem. When I click on the grid row, TabControls.SelectionChanged fires (WHY!!!?!?!!?!?!?!) and then the data is recalculated and rebound.
So the real question is why does click a DataGrid row cause the Parent TabControl's SelectionChanged Event to fire? Here's the XAML:
<Window xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="BPPDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BPPDemo"
Title="BPP Demo" Height="600" Width="700" Loaded="Window_Loaded">
<Window.Resources>
<local:AddrStatusColorConverter x:Key="addressStatusColorConverter"/>
<local:BoolToVisConverter x:Key="boolToVisConverter"/>
</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top">
<Menu.Items>
<MenuItem Header="File">
<MenuItem Header="Open Assessment" Command="{Binding SelectAssessmentCommand}"></MenuItem>
<MenuItem Header="Import Properties" Command="{Binding ImportPropertiesCommand}"></MenuItem>
</MenuItem>
<MenuItem Header="Properties" Visibility="{Binding IsSelected, ElementName=tabProperties,Converter={StaticResource boolToVisConverter}}">
<MenuItem Header="Delete All Properties" Command="{Binding DeleteAllPropertiesCommand}"></MenuItem>
<MenuItem Header="Resolve Invalid Addresses" Command="{Binding ValidateAddressesCommand}"></MenuItem>
<MenuItem Header="Select Situs" Command="{Binding SelectSitusCommand}"/>
</MenuItem>
</Menu.Items>
</Menu>
<DockPanel Margin="10">
<TextBlock Text="{Binding Assessment.Name}" FontWeight="Normal" FontSize="24" Foreground="#FF5C9EB7" DockPanel.Dock="Top" Margin="0,0,0,10"/>
<TabControl SelectionChanged="TabControl_SelectionChanged">
<TabItem x:Name="tabProperties" Header="Properties">
<DataGrid ItemsSource="{Binding Properties}" AutoGenerateColumns="False" IsReadOnly="True" SelectedItem="{Binding SelectedProperty,Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
<DataGridTextColumn Header="Cost" Binding="{Binding Cost,StringFormat='{}{0:c}'}"/>
<DataGridTextColumn Header="Year Acquired" Binding="{Binding YearAcquired}"/>
<DataGridTextColumn Header="Life In Years" Binding="{Binding LifeInYears}"/>
<DataGridTextColumn Header="Schedule" Binding="{Binding Schedule}"/>
<DataGridTextColumn Header="Current Value" Binding="{Binding CurrentValue,StringFormat='{}{0:c}'}" />
<DataGridTextColumn Header="Tax" Binding="{Binding Tax,StringFormat='{}{0:c}'}" />
<DataGridTemplateColumn Header="Address">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Address}" Foreground="{Binding AddressStatus, Converter={StaticResource addressStatusColorConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Address Status" Binding="{Binding AddressStatus}"/>
<DataGridTextColumn Header="Situs" Binding="{Binding Situs}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock>THIS ONE WORKS! WHY DOESN'T THE OTHER ONE????</TextBlock>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</TabItem>
<TabItem Header="Listings" Name="tabListings">
<DataGrid x:Name="SitusGroups" AutoGenerateColumns="false" SelectionMode="Single" SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Header="Situs" Binding="{Binding Situs,StringFormat='{}{0:c}',TargetNullValue='none'}"></DataGridTextColumn>
<DataGridTextColumn Header="Cost" Binding="{Binding Cost,StringFormat='{}{0:c}'}"></DataGridTextColumn>
<DataGridTextColumn Header="Value" Binding="{Binding Value,StringFormat='{}{0:c}'}"></DataGridTextColumn>
<DataGridTextColumn Header="Tax" Binding="{Binding Tax,StringFormat='{}{0:c}'}"></DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock>I JUST WANT TO SEE THIS WHEN I CLICK ON A ROW!</TextBlock>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</TabItem>
</TabControl>
</DockPanel>
</DockPanel>
The problem has to do with the way events are routed. TabControl and DataGrid derive from the same class, so when DataGrid SelectionChanged, my TabControl SelectionChanged handler was firing.
As the last comment at http://www.trentfguidry.net/post/2009/06/13/WPF-TabControl-SelectionChanged.aspx suggests, I checked the original source in my event handler and returned if the reference wasn't my tabcontrol.

Categories

Resources