ListView with footer row, right align column - c#

I've got this template for a ListView with a footer row. It uses gridview columns from the original ListView.
<Style x:Key="FrozenRowScrollViewer" TargetType="ScrollViewer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollViewer">
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DockPanel Margin="{TemplateBinding Padding}">
<ScrollViewer DockPanel.Dock="Bottom"
local:ScrollViewerBinding.HorizontalOffset="{Binding Value, ElementName=PART_HorizontalScrollBar}"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Focusable="false"
Visibility="{Binding TemplatedParent.HasFooter, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource booleanToVisibilityConverter}}">
<GridViewRowPresenter
Margin="2,0,2,0"
Content="{Binding Path=TemplatedParent.ItemsSource, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource summaryConverter}}"
Columns="{Binding Path=TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
<ScrollViewer DockPanel.Dock="Top"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Focusable="false">
<GridViewHeaderRowPresenter
Margin="2,0,2,0"
Columns="{Binding Path=TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderContainerStyle="{Binding Path=TemplatedParent.View.ColumnHeaderContainerStyle, RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderTemplate="{Binding Path=TemplatedParent.View.ColumnHeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderTemplateSelector="{Binding Path=TemplatedParent.View.ColumnHeaderTemplateSelector, RelativeSource={RelativeSource TemplatedParent}}"
AllowsColumnReorder="{Binding Path=TemplatedParent.View.AllowsColumnReorder, RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderContextMenu="{Binding Path=TemplatedParent.View.ColumnHeaderContextMenu, RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderToolTip="{Binding Path=TemplatedParent.View.ColumnHeaderToolTip, RelativeSource={RelativeSource TemplatedParent}}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
<ScrollContentPresenter Name="PART_ScrollContentPresenter"
KeyboardNavigation.DirectionalNavigation="Local"
CanContentScroll="True"
CanHorizontallyScroll="False"
CanVerticallyScroll="False" />
</DockPanel>
<ScrollBar Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{TemplateBinding HorizontalOffset}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
<ScrollBar Name="PART_VerticalScrollBar"
Grid.Column="1"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{TemplateBinding VerticalOffset}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ListView">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListViewItem" BasedOn="{StaticResource {x:Type ListViewItem}}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListView">
<Border Name="Border">
<ScrollViewer Style="{StaticResource FrozenRowScrollViewer}">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
There is a problem however with right aligned columns.
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Right" />
</Style>
The footer row stays left aligned while normal rows are displayed correctly. Why is that? The footer GridViewRowPresenter.Columns property is bound to the GridView used by other rows so it should align it also.
This also happens without a custom ItemContainerStyle:
<GridViewColumn local:SortingProperties.SortField="Hero.Stats.NetWon">
<GridViewColumnHeader Content="X Net won" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Hero.Stats.NetWon}" TextAlignment="Right" FontWeight="Bold" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Still left aligned but it is displayed in bold.

Okay, I drew a border around the right-aligned TextBlock and used snoop to figure out why the width of the column was wrong. Posting a solution if anyone needs it.
By using ListViewItem instead of bare GridViewRowPresenter it got to use proper column sizing:
<ListViewItem
GridView.ColumnCollection="{Binding Path=TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}"
Content="{Binding Path=TemplatedParent.ItemsSource, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource summaryConverter}}"
Style="{Binding Path=TemplatedParent.ItemContainerStyle, RelativeSource={RelativeSource TemplatedParent}}" />

<GridViewColumn local:SortingProperties.SortField="Hero.Stats.NetWon">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Hero.Stats.NetWon}" TextAlignment="Right" FontWeight="Bold" />
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumnHeader Content="X Net won" />
Try it.

Related

WPF ComboBox Ensure ItemTemple UserControl inherits Background And Foreground From ComboBox

I have a ComboBox,
<ComboBox Grid.Row="1"
Margin="5"
ItemsSource="{Binding PreviousGroups, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedGroup, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Style="{DynamicResource CBComboBoxStyle}"
ItemContainerStyle="{DynamicResource CBItemContainerStyle}">
<ComboBox.ItemTemplate>
<DataTemplate>
<objects:GroupNameObject GroupName="{Binding Path=Name}"
LastChecked="{Binding Path=LastVerified, StringFormat='dd - MM - yyyy |T| hh : mm : ss'}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
which uses the item template GroupNameObject
<UserControl x:Class="MyProject.Objects.GroupNameObject"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:fa="http://schemas.awesome.incremented/wpf/xaml/fontawesome.sharp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Name="groupNameObject">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MyProject;component/Assets/Colors.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Border Padding="3"
CornerRadius="10"
Margin="3"
HorizontalAlignment="Stretch">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background"
Value="Transparent" />
</Style>
</Border.Style>
<StackPanel Orientation="Horizontal">
<Grid Width="40"
Height="40"
Margin="5 2 3 2">
<Border CornerRadius="10"
Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBoxItem}}}" />
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<fa:IconImage Icon="Folder"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBoxItem}}}"
Width="30" />
</StackPanel>
</Grid>
<StackPanel>
<TextBlock Text="{Binding Path=GroupName, ElementName=groupNameObject}"
FontSize="20"
FontWeight="Bold"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBoxItem}}}"
Margin="5 0" />
<TextBlock FontSize="12"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBoxItem}}}"
Margin="5 3">
<Run Text="{Binding Path=LastChecked, ElementName=groupNameObject, StringFormat='MM / dd / yyyy |T| HH : mm : ss'}" />
</TextBlock>
</StackPanel>
</StackPanel>
</Border>
with the ItemContainerStyle
<Style x:Key="CBItemContainerStyle"
TargetType="{x:Type ComboBoxItem}">
<Setter Property="HorizontalContentAlignment"
Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
<Setter Property="VerticalContentAlignment"
Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
<Setter Property="Padding"
Value="3,0,3,0" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted"
Value="true">
<Setter Property="Background"
Value="{DynamicResource LemonCurry}" />
<Setter Property="Foreground"
Value="{DynamicResource LogoBlue}" />
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Background"
Value="{DynamicResource PansyPurple}" />
<Setter Property="Foreground"
Value="{DynamicResource LemonCurry}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When Built the DropDownItems inherit the Background and Foreground items correctly But the Displayed Item doesn't.
Display Item Example
DropDown Items Example
How Can I Change the Background and Foreground of the Displayed Item?
Edit:
Finally found a work around. instead of Binding the foreground and background of the GroupNameObject to the ComboBoxItem, I bound it to The ComboBox.
<StackPanel Orientation="Horizontal">
<Grid Width="40"
Height="40"
Margin="5 2 3 2">
<Border CornerRadius="10"
Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}" />
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<fa:IconImage Icon="Folder"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"
Width="30" />
</StackPanel>
</Grid>
<StackPanel>
<TextBlock Text="{Binding Path=GroupName, ElementName=groupNameObject}"
FontSize="20"
FontWeight="Bold"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"
Margin="5 0" />
<TextBlock FontSize="12"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"
Margin="5 3">
<Run Text="{Binding Path=LastChecked, ElementName=groupNameObject, StringFormat='MM / dd / yyyy |T| HH : mm : ss'}" />
</TextBlock>
</StackPanel>
</StackPanel>
and in the ItemContainerStyle I changed the Highlight Color to a diffrent shade so it doesn't clash with the ComboBox Colors.
<Trigger Property="IsHighlighted"
Value="true">
<Setter Property="Background"
Value="{DynamicResource BlueSapphire}" />
</Trigger>
Display Item After
DropDown Items After
You may have to override the ComboBox Template Property as well:
Example
<Style TargetType="ComboBox" BasedOn="{StaticResource baseStyle}">
<Setter ... />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid
x:Name="templateRoot"
UseLayoutRounding="True"
SnapsToDevicePixels="True"
>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="18" />
</Grid.ColumnDefinitions>
<Popup>
...
</Popup>
<ToggleButton>
...
</ToggleButton>
<ContentPresenter
x:Name="contentPresenter"
Grid.Column="0"
...
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
Inside this ToggleButton is the Layout for your ComboBox

Use a different item controls in WPF ListBox

I have a code like this:
<ListBox Name="lstBox"
ItemsSource="{Binding ViewModelsView}"
SelectedItem="{Binding SelectedAlertViewOutput, Mode=OneWayToSource}">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}" Padding="1" >
<ScrollViewer Padding="{TemplateBinding Padding}" >
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected"
Value="{Binding AlertRecord.IsSelected, Mode=TwoWay}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<controls:AlertExpander
Margin="1"
Value="{Binding AlertRecord.AlertCategory}"
IsExpanded="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
IsActive="{Binding AlertRecord.IsActive, Mode=OneWay }"
StartTime="{Binding AlertRecord.Timestamp, Mode=OneWay}"
StopTime="{Binding AlertRecord.EndTimestamp, Mode=OneWay}"
AlertId="{Binding AlertRecord.Id, Mode=OneWay}"
<controls:AlertExpander.Content>
<ContentPresenter>
</ContentPresenter>
</controls:AlertExpander.Content>
</controls:AlertExpander>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Style>
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:AlertUnknownViewModel}">
<local:AlertUnknownView></local:AlertUnknownView>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="4">
<ContentPresenter Content="{Binding}"></ContentPresenter>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
ListBox uses my control AlertExpander as ListBoxItem.
Is it possible to create a list consisting not only of elements of type AlertExpander? I would like for an element of another type to also use the parameters on which AlertExpander depends.
I have several types of controls that accept the same parameters as AlertExpander, but look different, and I need to display elements of all types in the list, not just AlertExpander.
AlertExpander.xaml:
<Expander
<Control.Style>
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<ToggleButton Name="HeaderButton">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="IsChecked" Value="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="IsEnabled" Value="{Binding Path=Expandable, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Border Grid.Row="1" BorderThickness="1" BorderBrush="Black"
CornerRadius="{Binding BorderCornerRadius, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Border>
<!-- Border shade -->
<Border Name="BorderShade" Grid.Row="1" BorderThickness="1" BorderBrush="Transparent" Visibility="Collapsed"
</Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2" Margin="10">
<Image.OpacityMask>
<ImageBrush ImageSource="{Binding SelectedItem.IconSource, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}"/>
</Image.OpacityMask>
<Image.Source>
<MultiBinding Mode="OneWay" Converter="{converters:GrayscaleImageSourceConverter}">
<Binding Path="SelectedItem" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
<Binding Path="IsActive" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
</MultiBinding>
</Image.Source>
</Image>
<StackPanel x:Name="topHeader" Grid.Row="0" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Bottom">
</StackPanel>
<Label x:Name="bottomHeader" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" Background="Transparent" Padding="0,2,0,0" FontSize="9pt"
Content="{Binding AlertHeaderTime, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="BorderShade" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Binding="{Binding IsAlertHeaderTimeShown, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}" Value="false">
<Setter TargetName="topHeader" Property="VerticalAlignment" Value="Center"/>
<Setter TargetName="topHeader" Property="Grid.RowSpan" Value="2"/>
<Setter TargetName="bottomHeader" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Border Grid.Row="1" BorderThickness="1" BorderBrush="Black"
CornerRadius="{Binding BorderCornerRadius, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay, Converter={converters:AlertExpanderCornerRadiusTopConverter}}">
</Border>
<!-- Border shade -->
<Border Name="BorderShade" Grid.Row="1" BorderThickness="1" BorderBrush="Transparent" Visibility="Collapsed"
Background="{Binding MouseOverShade, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}"
CornerRadius="{Binding BorderCornerRadius, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay, Converter={converters:AlertExpanderCornerRadiusTopConverter}}">
</Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2" Margin="10">
<Image.OpacityMask>
<ImageBrush ImageSource="{Binding SelectedItem.IconSource, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}"/>
</Image.OpacityMask>
<Image.Source>
<MultiBinding Mode="OneWay" Converter="{converters:GrayscaleImageSourceConverter}">
<Binding Path="SelectedItem" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
<Binding Path="IsActive" RelativeSource="{RelativeSource AncestorType=controls:AlertExpander}"/>
</MultiBinding>
</Image.Source>
</Image>
<StackPanel x:Name="topHeader" Grid.Row="0" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Bottom">
<Label Background="Transparent" Padding="0,0,0,2" FontSize="12pt"
FontWeight="{Binding IsActive, Mode=OneWay, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Converter={converters:BoolToFontWeightConverter}}"
Content="{Binding AlertHeader, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
<Label Background="Transparent" Padding="4,0,0,2" FontSize="12pt"
FontWeight="{Binding IsActive, Mode=OneWay, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Converter={converters:BoolToFontWeightConverter}}"
Visibility="{Binding IsActive, Mode=OneWay, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Converter={converters:InactiveNoteVisibilityConverter}}"
Content="{Binding InactiveNote, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
</StackPanel>
<Label x:Name="bottomHeader" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" Background="Transparent" Padding="0,2,0,0" FontSize="9pt"
Content="{Binding AlertHeaderTime, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}">
</Label>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="BorderShade" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Binding="{Binding IsAlertHeaderTimeShown, RelativeSource={RelativeSource AncestorType=controls:AlertExpander}, Mode=OneWay}" Value="false">
<Setter TargetName="topHeader" Property="VerticalAlignment" Value="Center"/>
<Setter TargetName="topHeader" Property="Grid.RowSpan" Value="2"/>
<Setter TargetName="bottomHeader" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<!-- Content -->
<ScrollViewer Name="ContentScrollViewer" Grid.Row="1"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Bottom"
Visibility="Visible">
<Border Name="ExpanderContentBorder" BorderThickness="1,0,1,1" BorderBrush="Black">
<ContentPresenter ContentSource="Content"/>
</Border>
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Control.Style>
enter image description here
Before I get to the code, I want to point out that this is a job for data templates, rather than control templates.
The Template property takes a ControlTemplate and is used to define the structure of a control. This is usually used when you are building a control from scratch or significantly altering one. What you want to do is just change how your data is being displayed inside an existing control. For that, there are DataTemplate properties, such as ItemTemplate.
With that out of the way, I put together some code for you that should at least point you in the right direction:
<ListBox Name="lstBox" ItemsSource="{Binding ViewModelsView}" SelectedItem="{Binding SelectedAlertViewOutput, Mode=OneWayToSource}">
<ListBox.Resources>
<DataTemplate DataType="local:AlertRecord" x:Key="AlertExpanderItem">
<controls:AlertExpander Margin="1"
Value="{Binding AlertCategory}"
IsExpanded="{Binding IsSelected, Mode=TwoWay}"
IsActive="{Binding IsActive, Mode=OneWay }"
StartTime="{Binding Timestamp, Mode=OneWay}"
StopTime="{Binding EndTimestamp, Mode=OneWay}"
AlertId="{Binding Id, Mode=OneWay}"/>
</DataTemplate>
<DataTemplate DataType="local:AlertRecord" x:Key="OtherControlItem">
<controls:OtherControl Margin="1"
Value="{Binding AlertCategory}"
IsExpanded="{Binding IsSelected, Mode=TwoWay}"
IsActive="{Binding IsActive, Mode=OneWay }"
StartTime="{Binding Timestamp, Mode=OneWay}"
StopTime="{Binding EndTimestamp, Mode=OneWay}"
AlertId="{Binding Id, Mode=OneWay}"/>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{StaticResource OtherControlItem}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Value}" Value="0">
<Setter Property="ContentTemplate" Value="{StaticResource AlertExpanderItem}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
...
public class AlertRecord
{
...
public bool HasPositiveValue { get { return Value >= 0 } }
...
}
I start by defining two different ItemTemplates inside inside the Resources of the ListBox. You would define one for each of the different controls you need to use. Notice that I left off "AlertRecord." from the bindings. That is because each DataTemplate instance will have the AlertRecord as its DataContext.
For the ItemTemplate property, I borrowed from this answer here: https://stackoverflow.com/a/10191762/5086631. I made a DataTemplate with a ContentControl and used the Style to change the ContentTemplate based on DataTriggers. This lets you change the template based on the properties of your list item.
Based on your comment, the style is set up so that "OtherControlItem" (the non-expander control) is used by default, and AlertExpanderItem is used when HasPositiveValue returns true. HasPositiveValue is a property you would need to add to AlertRecord.

xaml style all datagrid 'select all' buttons in specific style name

Based on the answers here, to style a data grids top left corner (the select all button), I can do something like this:
<Style TargetType="{x:Type Button}"
x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle,
TypeInTargetAssembly={x:Type DataGrid}}">
<Setter Property="BorderBrush" Value="#FFf2f2f2"/>
<Setter Property="BorderThickness" Value="0, 0, 1, 0"/>
<Setter Property="Background" Value="#FFf9f9f9"/>
</Style>
The thing is, I do not want this style globally, but I do want to be able to re-use this style. I know I could copy/paste it into specific data grids, but I would prefer to keep it reusable. Is this possible, by somehow applying a property to the datagrid?
Try this:
<Window x:Class="WpfApplication276.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication276"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type Button}"
x:Key="SelectAllButtonStyle1">
<Setter Property="BorderBrush" Value="#FFf2f2f2"/>
<Setter Property="BorderThickness" Value="0, 0, 1, 0"/>
<Setter Property="Background" Value="Red"/>
</Style>
<Style x:Key="DataGridStyle1" TargetType="{x:Type DataGrid}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderBrush" Value="#FF688CAF"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource SelectAllButtonStyle1}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
<Grid Grid.Column="1" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Window.DataContext>
<local:MyViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<DataGrid x:Name="dataGrid1" ItemsSource="{Binding Data}" Style="{DynamicResource DataGridStyle1}" />
<DataGrid x:Name="dataGrid2" ItemsSource="{Binding Data}"/>
</StackPanel>
</Grid>
You can also make it a little less verbose by customizing only the datagrid's Template:
<Style TargetType="{x:Type Button}"
x:Key="SelectAllButtonStyle1">
<Setter Property="BorderBrush" Value="#FFf2f2f2"/>
<Setter Property="BorderThickness" Value="0, 0, 1, 0"/>
<Setter Property="Background" Value="Red"/>
</Style>
<ControlTemplate x:Key="ControlTemplate1" TargetType="{x:Type DataGrid}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource SelectAllButtonStyle1}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
<Grid Grid.Column="1" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
And then similarly applying it like before:
<StackPanel>
<DataGrid x:Name="dataGrid1"
ItemsSource="{Binding Data}"
Template="{DynamicResource ControlTemplate1}" />
<DataGrid x:Name="dataGrid2"
ItemsSource="{Binding Data}" />
</StackPanel>

How do I add a footer row in a WPF datagrid?

How Do I Add a footer row in WPF datagrid? I had to add a row in a WPF datagrid for the sum of each column, I don't want to use any dll or telerik and some things like that only use Microsoft components to do this. I'm trying to do it this way:
<Style TargetType="{x:Type DataGrid}">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="{DynamicResource BorderLightColor}" Offset="0" />
<GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="1" />
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="Both" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border x:Name="border"
SnapsToDevicePixels="True"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<Border.Background>
<SolidColorBrush Color="{DynamicResource ControlLightColor}" />
</Border.Background>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="border"
Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="{DynamicResource ControlLightColor}" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Normal" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false" Background="Black">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Focusable="false"
Command="{x:Static DataGrid.SelectAllCommand}"
Style="{DynamicResource {ComponentResourceKey
ResourceId=DataGridSelectAllButtonStyle,
TypeInTargetAssembly={x:Type DataGrid}}}"
Visibility="{Binding HeadersVisibility,
ConverterParameter={x:Static DataGridHeadersVisibility.All},
Converter={x:Static DataGrid.HeadersVisibilityConverter},
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
Width="{Binding CellsPanelHorizontalOffset,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter"
Grid.Column="1"
Visibility="{Binding HeadersVisibility,
ConverterParameter={x:Static DataGridHeadersVisibility.Column},
Converter={x:Static DataGrid.HeadersVisibilityConverter},
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
Grid.ColumnSpan="2"
Grid.Row="1"
CanContentScroll="{TemplateBinding CanContentScroll}" />
<ScrollBar x:Name="PART_VerticalScrollBar"
Grid.Column="2"
Grid.Row="1"
Orientation="Vertical"
ViewportSize="{TemplateBinding ViewportHeight}"
Maximum="{TemplateBinding ScrollableHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{Binding VerticalOffset, Mode=OneWay,
RelativeSource={RelativeSource TemplatedParent}}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="This is footer!"/>
<Grid Grid.Column="1" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar"
Grid.Column="1"
Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportWidth}"
Maximum="{TemplateBinding ScrollableWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</Trigger>
</Style.Triggers>
</Style>
I also tried adding a grid instead of textblock, but when resizing datagrid columns, they can't resize and looks very ugly.
Try this.
<ScrollViewer VerticalAlignment="Top" HorizontalScrollBarVisibility="Auto">
<StackPanel>
<DataGrid ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<DataGrid.Columns>
<DataGridTextColumn x:Name="Header1" Header="Header1"></DataGridTextColumn>
<DataGridTextColumn x:Name="Header2" Header="Header2"></DataGridTextColumn>
<DataGridTextColumn x:Name="Header3" Header="Header3"></DataGridTextColumn>
</DataGrid.Columns>
<TextBlock></TextBlock>
<TextBlock></TextBlock>
</DataGrid>
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
<Grid Width="{Binding ElementName=Header1,Path=ActualWidth}">
<TextBlock Margin="5,0,0,0" Text="Footer1"></TextBlock>
</Grid>
<Grid Width="{Binding ElementName=Header2,Path=ActualWidth}">
<TextBlock Text="Footer2" Margin="5,0,0,0"></TextBlock>
</Grid>
<Grid Width="{Binding ElementName=Header3,Path=ActualWidth}">
<TextBlock Text="Footer3" Margin="5,0,0,0"></TextBlock>
</Grid>
</StackPanel>
</StackPanel>
</ScrollViewer>
Result
Answer By Heena Patil has some issues.
When the layout of the DataGrid changes, like when the scrollbar is visible or window resized. Then the position of footer changes.
The concept is to set the margin-left and width of the footer TextBlocks
when the layout is updated.
<DataGrid x:Name="DGSalesINvoice" LayoutUpdated="DG_LayoutUpdated">
<DataGridTextColumn x:Name="DG_COL_IdSalesInvoice" Width="Auto" Header="ID" Binding="{Binding IdSalesInvoice}" />
<DataGridTextColumn x:Name="DG_COL_CustomerName" Width="*" Header="Customer" Binding="{Binding CustomerName}" />
<DataGridTemplateColumn x:Name="DG_COL_SalesInvoiceAmount" Width="Auto" Header="Invoice Amount">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Right" Text="{Binding SalesAmount}"></TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="DG_COL_EditBtn" Width="50">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btnEditCompany" Tag="{Binding IdSalesInvoice}">Edit</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
<StackPanel Orientation="Horizontal" Grid.Row="2" Background="GhostWhite">
<TextBlock x:Name="lblTotal" TextAlignment="Right" FontWeight="Bold">Total</TextBlock>
<TextBlock x:Name="lblTotalSalesInvoiceAmount" TextAlignment="Right" FontWeight="Bold">0.00</TextBlock>
</StackPanel>
private void DGSalesINvoice_LayoutUpdated(object sender, EventArgs e)
{
Thickness t = lblTotal.Margin;
t.Left = (DGSalesINvoice.Columns[0].ActualWidth + 7);
lblTotal.Margin = t;
lblTotal.Width = DGSalesINvoice.Columns[1].ActualWidth;
lblTotalSalesInvoiceAmount.Width = DGSalesINvoice.Columns[2].ActualWidth;
}

C# WPF: prevent last item cover by horizontal scrollbar in ListView with Height property set to "Auto"

I have a WPF ListView inside StackPanel, with Height="Auto". It's great that it does what I wanted to - changes it's height according to the all items contained in ListView. I have also HorizontalScrollBarVisiblity="Auto" on my ListView, which suits my needs.
The problem occurs when the whole width of columns of my ListView is greater than width of ListView control (i.e. user decreases width of a window and this control). In that case obviously horizontal scrollbar appears - thats ok. The problem is that this scrollbar covers last (bottom) item of the ListView's items so it is partially not visible.
Vertical scrollbar doesn't appear and this is ok - I don't want it. I just want to have my ListView height beeing calculated properly, so it considers the height of shown horizontal scrollbar and includes it in calculation so all items are wholy visible.
Xaml code example:
<ListView Name="lvProcedures" ItemsSource="{Binding Path=Procedures}" SelectionMode="Single">
<ListView.View>
<GridView AllowsColumnReorder="False" ColumnHeaderToolTip="Lista zabiegów">
<GridViewColumn DisplayMemberBinding="{Binding Path=procedure}" Header="A" Width="150" />
<GridViewColumn DisplayMemberBinding="{Binding Path=location}" Header="B" Width="100" />
<GridViewColumn DisplayMemberBinding="{Binding Path=material}" Header="C" Width="180" />
<GridViewColumn DisplayMemberBinding="{Binding Path=other}" Header="D" Width="180" />
<GridViewColumn DisplayMemberBinding="{Binding Path=description}" Header="E" Width="400" />
</GridView>
</ListView.View>
</ListView>
I've now hanged on idea to create user control (maybe only ListView's derieved class??) which overrides MeasureOverride but I don't think it is good way to solve such a small but iritating "bug" and it also still makes me trouble to implement the solution.
Can somebody provide some elegant solution for this problem?
Any idea would be appreciated.
#bartivo: I'm not getting the same result as you - the bottom horizontal scrollbar doesn't appear to obscure the lowest item. I'm wondering if you're using a custom ControlTemplate for your ListView and ScrollViewer, b/c the default ScrollViewer template has two rows the ScrollContentPresenter in the first (Height="*") and the HorizontalScrollBar in the 2nd row (Height="Auto") thus ensuring that the one doesn't overlap the other.
Maybe you could try using these styles for your ListView and ScrollViewer and see if that problem still occurs:
<SolidColorBrush x:Key="ListBorder" Color="#828790"/>
<Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}" TargetType="{x:Type ScrollViewer}">
<Setter Property="Focusable" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid SnapsToDevicePixels="true" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Margin="{TemplateBinding Padding}">
<ScrollViewer Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" DockPanel.Dock="Top">
<GridViewHeaderRowPresenter Margin="2,0,2,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" AllowsColumnReorder="{Binding TemplatedParent.View.AllowsColumnReorder, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContainerStyle="{Binding TemplatedParent.View.ColumnHeaderContainerStyle, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContextMenu="{Binding TemplatedParent.View.ColumnHeaderContextMenu, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderStringFormat="{Binding TemplatedParent.View.ColumnHeaderStringFormat, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplate="{Binding TemplatedParent.View.ColumnHeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplateSelector="{Binding TemplatedParent.View.ColumnHeaderTemplateSelector, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderToolTip="{Binding TemplatedParent.View.ColumnHeaderToolTip, RelativeSource={RelativeSource TemplatedParent}}" Columns="{Binding TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}"/>
</ScrollViewer>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.DirectionalNavigation="Local" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}"/>
</DockPanel>
<ScrollBar x:Name="PART_HorizontalScrollBar" Cursor="Arrow" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Grid.Row="1" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0.0" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Cursor="Arrow" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0.0" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}"/>
<DockPanel Background="{Binding Background, ElementName=PART_VerticalScrollBar}" Grid.Column="1" Grid.Row="1" LastChildFill="false">
<Rectangle Fill="White" Width="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" DockPanel.Dock="Left"/>
<Rectangle Fill="White" Height="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" DockPanel.Dock="Top"/>
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ListViewStyle1" TargetType="{x:Type ListView}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="#FF042271"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListView}">
<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding IsMouseOver}">
<ScrollViewer Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Microsoft_Windows_Themes:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Categories