Cannot handle button tap in ListView ItemTemplate - wpf

I have a ListView with custom ItemContainer and ItemTemplate. ItemTemplate contains, among other controls, a button. Whenever I click or tap a button ListView a whole item is selected, in contrast to the expected button click or tap event to be fired. I've noticed that the only time the button is clickable is when I position mouse cursor at the top border of the button (whichi is also the only time I am getting the default mouse over effect).
Here is the XAML:
<Style TargetType="ListView" x:Key="SalesOrdersListViewStyle">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="SelectionMode" Value="Single" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListViewItem">
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<!--<Setter Property="Background" Value="Transparent"/>-->
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="Padding" Value="12,6"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}"/>
<Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter
Foreground="{StaticResource HighlightPressedBrush}"
CheckBrush="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
ContentMargin="{TemplateBinding Padding}"
CheckMode="Inline"
ContentTransitions="{TemplateBinding ContentTransitions}"
CheckBoxBrush="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
DragForeground="{ThemeResource ListViewItemDragForegroundThemeBrush}"
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
DragBackground="{ThemeResource ListViewItemDragBackgroundThemeBrush}"
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
FocusBorderBrush="{ThemeResource SystemControlForegroundAltHighBrush}"
FocusSecondaryBorderBrush="{ThemeResource SystemControlForegroundBaseHighBrush}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
PointerOverForeground="{StaticResource HighlightPressedBrush}"
PressedBackground="{ThemeResource HighlightAlternativePressedBrush}"
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}"
PointerOverBackground="{ThemeResource HighlightPointerOverBrush}"
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
SelectedPressedBackground="{ThemeResource ControlBackgroundDarkBrush}"
SelectionCheckMarkVisualEnabled="True"
SelectedForeground="#FFFFFFFF"
SelectedPointerOverBackground="{ThemeResource HighlightAlternativePointerOverBrush}"
SelectedBackground="{ThemeResource HighlightPressedBrush}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock
x:Uid="SalesOrderNumber"
Grid.Row="0" Grid.Column="1" />
<TextBlock
Grid.Row="0" Grid.Column="2"
Text="{Binding Number}" />
<!-- TEST BUTTON THAT CANNOT BE TAPPED -->
<Button
Grid.Row="0" Grid.RowSpan="4" Grid.Column="3"
HorizontalAlignment="Left" VerticalAlignment="Center"
Background="Red"
IsHitTestVisible="True"
Content="TEST" />
<TextBlock
x:Uid="DeliveryMode"
Grid.Row="1" Grid.Column="1" />
<TextBlock
Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2"
Text="{Binding DeliveryMode}" /
<TextBlock
x:Uid="ShippingDate"
Grid.Row="2" Grid.Column="1" />
<TextBlock
Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2"
Text="{Binding ShippingDate}" />
<TextBlock
x:Uid="ProjectNumber"
Grid.Row="3" Grid.Column="1" />
<TextBlock
Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2"
Text="{Binding ProjectNumber}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
How do I make the button click or tap event to fire instead of selecting an item?
Note: I just commented out the entire <Setter Property="ItemContainerStyle"> and the issue is still there.

The problem is in you TextBlocks with Grid.Column="2" Grid.ColumnSpan="2". Set ColumSpan to 1 and it will work.

I am a total newbie but couldn't you just add a Button click event?
<Button
Grid.Row="0" Grid.RowSpan="4" Grid.Column="3"
HorizontalAlignment="Left" VerticalAlignment="Center"
Background="Red"
IsHitTestVisible="True"
Click"btn_Click"
Content="TEST" />
And in the code:
private void btn_Click(object sender, RoutedEventArgs e)
{
// Do stuff
}
I hope I don't talk bullsh*t here but I don't see your click event anywhere.

Related

Center a vertically oriented grid in wpf

I started doing the UI for an app in WinForm but I just read about WPF and I decided to re-do my work on it. But since is a new think I ran in a small problem:
As you can see in the screenshot bellow I have 3 vertical buttons that are centered on the main form. How can I achieve the same thing in WPF? I've tried any value I could find to change position but all of them failed.
Here is my main form XAML:
<Window x:Class="YouTubeMusicPlayerWpf.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:local="clr-namespace:YouTubeMusicPlayerWpf"
xmlns:fa="http://schemas.fontawesome.io/icons/"
mc:Ignorable="d" Height="500" Width="900" Background="Black" WindowStyle="None" AllowsTransparency="true" WindowStartupLocation="CenterScreen" Name="mainWindow">
<WindowChrome.WindowChrome>
<WindowChrome ResizeBorderThickness="6" CornerRadius="0" GlassFrameThickness="0">
</WindowChrome>
</WindowChrome.WindowChrome>
<StackPanel Background="#FF201E2B">
<!-- TitleBar buttons -->
<Grid HorizontalAlignment="Right">
<StackPanel Orientation="Horizontal">
<Button fa:Awesome.Content="WindowMinimize" Background="Transparent" Foreground="White" VerticalAlignment="Stretch" Padding="8" BorderThickness="0" WindowChrome.IsHitTestVisibleInChrome="True" Name="minButton" Click="MinButton_OnClick"></Button>
<Button fa:Awesome.Content="WindowMaximize" Background="Transparent" Foreground="White" VerticalAlignment="Stretch" Padding="8" BorderThickness="0" WindowChrome.IsHitTestVisibleInChrome="True" Name="maxButton" Click="MaxButton_OnClick"></Button>
<Button fa:Awesome.Content="WindowClose" Background="Transparent" Foreground="White" VerticalAlignment="Stretch" Padding="8" BorderThickness="0" WindowChrome.IsHitTestVisibleInChrome="True" Name="closeButton" Click="CloseButton_OnClick"></Button>
</StackPanel>
</Grid>
<!-- Menu Buttons-->
<Grid HorizontalAlignment="Left" VerticalAlignment="Center">
<StackPanel Orientation="Vertical">
<Button fa:Awesome.Content="Youtube" FontSize="40" Background="#00000000" Foreground="White" BorderBrush="Transparent" Width="80" Height="80" VerticalAlignment="Center" HorizontalAlignment="Center"></Button>
<Button fa:Awesome.Content="Music" FontSize="40" Background="#00000000" Foreground="White" BorderBrush="Transparent" Width="80" Height="80" VerticalAlignment="Center" HorizontalAlignment="Center"></Button>
<Button fa:Awesome.Content="Download" FontSize="40" Background="#00000000" Foreground="White" BorderBrush="Transparent" Width="80" Height="80" VerticalAlignment="Center" HorizontalAlignment="Center"></Button>
</StackPanel>
</Grid>
</StackPanel>
</Window>
The problem is your root element. Replace the StackPanel by a grid and problem solved.
Bonus : if you are new to WPF, I show you how to refactorize your styles.
<Grid Background="Black">
<Grid.Resources>
<!-- Exemple of a style with a key to reuse -->
<Style x:Key="LeftButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="40" />
<Setter Property="Width" Value="80" />
<Setter Property="Height" Value="80" />
<Setter Property="Background" Value="#00000000" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Grid.Resources>
<!-- TitleBar buttons -->
<StackPanel
HorizontalAlignment="Right"
VerticalAlignment="Top"
Orientation="Horizontal">
<StackPanel.Resources>
<!-- Exemple of a implicit styles that will be set to each child with a matching type -->
<!-- Notice there is no x:Key -->
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Padding" Value="8" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</StackPanel.Resources>
<Button Content="b1" />
<Button Content="b2" />
<Button Content="b3" />
</StackPanel>
<!-- Menu Buttons -->
<StackPanel
HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Vertical">
<Button Content="icon" Style="{StaticResource LeftButtonStyle}" />
<Button Content="icon" Style="{StaticResource LeftButtonStyle}" />
<Button Content="icon" Style="{StaticResource LeftButtonStyle}" />
</StackPanel>
</Grid>
Notice there is neither RowDefinitions nor ColumnDefinitions.
Here is how to do the same thing with place to set the content (a red box for exemple).
<Grid Background="Black">
<Grid.Resources>
<!-- Exemple of a style with a key to reuse -->
<Style x:Key="LeftButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="40" />
<Setter Property="Width" Value="80" />
<Setter Property="Height" Value="80" />
<Setter Property="Background" Value="#00000000" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- TitleBar buttons -->
<StackPanel
Grid.Column="1"
HorizontalAlignment="Right"
Orientation="Horizontal">
<StackPanel.Resources>
<!-- Exemple of a implicit styles that will be set to each child with a matching type -->
<!-- Notice there is no x:Key -->
<Style TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Padding" Value="8" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</StackPanel.Resources>
<Button Content="b1" />
<Button Content="b2" />
<Button Content="b3" />
</StackPanel>
<!-- Menu Buttons -->
<StackPanel
Grid.RowSpan="2"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Vertical">
<Button Content="icon" Style="{StaticResource LeftButtonStyle}" />
<Button Content="icon" Style="{StaticResource LeftButtonStyle}" />
<Button Content="icon" Style="{StaticResource LeftButtonStyle}" />
</StackPanel>
<Grid Background="Red" Grid.Row="1" Grid.Column="1"/>
</Grid>

WPF nested template binding in itemscontrol

I have a problem with nested template bindings.
Having an ItemsControl with a template, which works great. This template contains a tooltip as well (which shows perfectly).
<Button.ToolTip>
<TextBlock Text="{Binding Path=DetailPaneText}" />
</Button.ToolTip>
But inside the itemscontrol template, I have a ToggleButton with another template inside it. And I can't seem to show the text over there as well since the binding isn't correct.
Code inside the toggle button
<StackPanel Background="#293344" Width="200" x:Name="DetailTab" Margin="0">
<TextBlock FontSize="12" Text="" Foreground="White" />
</StackPanel>
What kind of binding or syntax should I put in between the Text tags? I tried several options but none of them seemed to work yet. Currently out of guesses.
Thanks
Complete code snippet
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0" >
<Button Command="{x:Static CobraInfrastructure:Commands.NavigateFromBreadcrumb}" CommandParameter="{Binding Path=Current}" Tag="{Binding DetailPaneText}" x:Name="TextBlock_Detail" Style="{DynamicResource BreadcrumbButton}">
<Button.Resources>
<Style BasedOn="{StaticResource {x:Type ToolTip}}" TargetType="ToolTip">
<Setter Property="Background" Value="#F8F8F8" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Padding" Value="15" />
<Setter Property="MinWidth" Value="300" />
<Setter Property="MinHeight" Value="150" />
<Setter Property="VerticalAlignment" Value="Top" />
</Style>
</Button.Resources>
<Button.ToolTip>
<TextBlock Text="{Binding Path=DetailPaneText}" />
</Button.ToolTip>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="HyphenTextBlock" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding Path=EntityTitle}" FontSize="12" FontWeight="Bold" Foreground="White" Grid.Row="0" Grid.Column="0"/>
<TextBlock VerticalAlignment="Stretch" Text="{Binding Path=Text, NotifyOnTargetUpdated=True, Mode=OneWay}" FontSize="10" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
</Grid>
</Button>
<ToggleButton Focusable="False" Style="{DynamicResource BreadcrumbOpenButton}" VerticalAlignment="Stretch" HorizontalAlignment="Center" Tag="{Binding Path=DetailPaneText}">
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel Orientation="Horizontal">
<Border Width="13" Background="#293344">
<fa:FontAwesome Icon="CaretRight" Foreground="White" FontSize="18" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
<StackPanel Background="#293344" Width="200" x:Name="DetailTab" Margin="0">
<TextBlock FontSize="12" Text="" Foreground="White" />
</StackPanel>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Width" TargetName="DetailTab" Value="200"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Width" TargetName="DetailTab" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding IsOverview}" Value="True">
<Setter Property="Style" TargetName="TextBlock_Detail" Value="{DynamicResource LinkButton}" />
<Setter Property="FontWeight" TargetName="TextBlock_Detail" Value="Bold" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
You should reference on TemplatedParent in Binding:
<StackPanel Background="#293344" Width="200" x:Name="DetailTab" Margin="0">
<TextBlock FontSize="12" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.DetailPaneText}" Foreground="White" />
</StackPanel>
If you trying to bind a tooltip text of a button to the Text property of textblock, you may bind it using the ElementName.
First name your button using x:Name
<Button x:Name="XButton">
<Button.ToolTip>
<TextBlock Text="{Binding Path=DetailPaneText}" />
</Button.ToolTip>
</Button>
Bind it to text block text using the ElementName.
<StackPanel Background="#293344" Width="200" x:Name="DetailTab" Margin="0">
<TextBlock FontSize="12" Text="{Binding ElementName=XButton, Path=ToolTip.Text}" />
</StackPanel>

Border widths displays inconsistently

Lets take this as example. I now have a total of 8 textboxes. I use a static resource style to make sure they all have the exact same styling set. But notice how some of the textboxes have a bottom border line and others don't. Why does this happen?
Here's the code
<Style x:Key="AddressTextBox" TargetType="TextBox">
<Setter Property="MinWidth" Value="230"></Setter>
<Setter Property="MaxWidth" Value="260"></Setter>
<Setter Property="MaxLength" Value="45"></Setter>
<Setter Property="Margin" Value="1"></Setter>
<Setter Property="BorderThickness" Value="1,1,1,1"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Padding" Value="1,2,0,1"/>
<Setter Property="BorderBrush" Value="Gray"></Setter>
<Setter Property="Height" Value="20"></Setter>
</Style>
<DockPanel>
<StackPanel>
<Grid Margin="5">
<StackPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7">Postal</TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7"></TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7"></TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7"></TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
<DockPanel Height="10"></DockPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7">Street</TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7"></TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7"></TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
<DockPanel Height="Auto">
<TextBlock Width="50" Margin="7"></TextBlock>
<TextBox Style="{StaticResource AddressTextBox}"></TextBox>
</DockPanel>
</StackPanel>
</Grid>
</StackPanel>
</DockPanel>
Even though your layout is very inefficient, its not the problem as all above comments suggest. Nothing to do with SnapToDevicePixels, Padding, Margins, etc. It is part of TextBox's control style. It seems that if you set BorderWidth bigger than default, it sticks on all corners, but if you go below it doesn't. If you extract the TextBox's template you can see its border and styling. So in order to "beat" this irregularity, instead of trying to sort of indirectly manipulate the TextBox's Border properties in your style you need to override its template. Then manipulate it's Border directly in the Template.
Here's a the style that will work(I plugged in your setters into it) :
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="LightGray"/>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="Gray"/>
<SolidColorBrush x:Key="EnabledBackgroundBrush" Color="White"/>
<Style x:Key="AddressTextBox" TargetType="{x:Type TextBoxBase}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="MinWidth" Value="230"/>
<Setter Property="MaxWidth" Value="260"/>
<Setter Property="Margin" Value="1"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Padding" Value="1,2,0,1"/>
<Setter Property="Height" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border Name="Border" CornerRadius="2" Padding="2" Background="{StaticResource EnabledBackgroundBrush}"
BorderBrush="Gray" BorderThickness="1" >
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}"/>
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBackgroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
also, just a tip about your layout. To minimize inefficiencies, I would use the Grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="Postal"/>
<TextBox Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
<TextBlock Grid.Row="1" />
<TextBox Grid.Row="1" Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
<TextBlock Grid.Row="2" />
<TextBox Grid.Row="2" Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
<TextBlock Grid.Row="3" />
<TextBox Grid.Row="3" Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
<TextBlock Grid.Row="4" Text="Street" Margin="7,10,7,7"/>
<TextBox Grid.Row="4" Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
<TextBlock Grid.Row="5"/>
<TextBox Grid.Row="5" Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
<TextBlock Grid.Row="6"/>
<TextBox Grid.Row="6" Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
<TextBlock Grid.Row="7"/>
<TextBox Grid.Row="7" Grid.Column="1" Style="{StaticResource AddressTextBox}"/>
</Grid>

WPF ListBox items with template become invisible after grouping

I have ObservableCollection with items which I want to display in a ListBox.
Also I write a template for ListboxItem for correct display of my collection.
On this stage everything works fine.
in .cs
Sensors = new ObservableCollection<Sensor>();
...
lstBox.ItemsSource = Sensors;
in .xaml
...
<DataTemplate x:Key="SensorTileTemplate">
<Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Grid.Row="0" Grid.ColumnSpan="3"></TextBlock>
<Image Source="{Binding ImageModel.ImgSource}" Style="{StaticResource ImageGlowStyle}" Height="72" Grid.Row="1" Grid.Column="0"></Image>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5">
<TextBlock Text="IP:"></TextBlock>
<TextBlock Text="Port:"></TextBlock>
<TextBlock Text="Command port:"></TextBlock>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="2" Margin="5">
<TextBlock Text="{Binding DeviceAddress}"></TextBlock>
<TextBlock Text="{Binding DeviceDataPort}"></TextBlock>
<TextBlock Text="{Binding DeviceControlPort}"></TextBlock>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
<Style x:Key="ContainerStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="ListBoxItem.Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
...
<ListBox Name="lstBox" Focusable="False"
SelectionChanged="lstBox_SelectionChanged"
HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource SensorTileTemplate}"
ItemContainerStyle="{StaticResource ContainerStyle}">
</ListBox>
The problem appears when I need to group certain items using expander as a group container.
in .cs
...
ICollectionView view = CollectionViewSource.GetDefaultView(Sensors);
view.GroupDescriptions.Add(new PropertyGroupDescription("GroupNumber"));
lstBox.ItemsSource = view;
...
in .xaml
<!--Same Template and Style-->
...
...
<Style x:Key="GroupContainerStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Group #" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
...
<ListBox Name="lstBox" Focusable="False"
SelectionChanged="lstBox_SelectionChanged"
HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource SensorTileTemplate}"
ItemContainerStyle="{StaticResource ContainerStyle}">
<ListBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupContainerStyle}" />
</ListBox.GroupStyle>
</ListBox>
This code works and groups items but items become invisible.
So without grouping items display correctly but with grouping expanders show nothing in it.
I think there is something about ItemsPresenter in Expander but can't figure out what.
The problem was in one third party theme I use in my app. That theme has a ListBox template like:
<Style TargetType="{x:Type ListBox}">
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid>
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2" Background="{DynamicResource ControlBackgroundBrush}" />
<ScrollViewer Margin="1" Style="{DynamicResource NuclearScrollViewer}" Focusable="false" Background="{x:Null}">
<StackPanel Margin="1,1,1,1" IsItemsHost="true" />
</ScrollViewer>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border" />
<Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So I use an ItemsPresenter instead of the StackPanel in that template and everything works now.

How can I set ContentPropertyAttribute to a Content Presenter?

I have a Usercontrol: SnazzyForm, which in addition to a couple of borders and and a header area and whatnot, also has a Content Presenter which under .NET Framework 3.5 presented content passed to it in other forms that used the control just fine.
However after moving the project to 4.0 I am greeted with "Cannot add content to object of type" blah blah blah.
The codebehind for the control is thus:
Imports System
Imports System.IO
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.ComponentModel
Public Class SnazzyForm
Inherits ContentControl
Public Shared TitleProperty As DependencyProperty = DependencyProperty.Register("Title", GetType(String), GetType(SnazzyForm))
<Description("Title to display"), _
Category("Custom")> _
Public Property Title() As String
Get
Return CType(GetValue(TitleProperty), String)
End Get
Set(ByVal value As String)
SetValue(TitleProperty, value)
End Set
End Property
Shared Sub New()
' Insert code required on object creation below this point.
DefaultStyleKeyProperty.OverrideMetadata(GetType(SnazzyForm), New FrameworkPropertyMetadata(GetType(SnazzyForm)))
End Sub
End Class
The template in the resourcedictionary that governs this control is thus:
<Style TargetType="{x:Type local:SnazzyForm}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SnazzyForm}">
<ControlTemplate.Resources>
<Style TargetType="{x:Type Border}" x:Key="formOuterBorderStyle">
<Setter Property="Margin" Value="22,22,22,3" />
<Setter Property="Padding" Value="0" />
<Setter Property="BorderBrush" Value="{StaticResource BrushBorder}" />
<Setter Property="BorderThickness" Value="3" />
<Setter Property="Background" Value="{StaticResource BrushBackgroundDark}" />
<Setter Property="CornerRadius" Value="20,20,0,0" />
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="formTitleStyle">
<Setter Property="Foreground" Value="{StaticResource BrushWhiteSmoke}" />
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Padding" Value="11,7,7,7" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="formBreadcrumbStyle">
<Setter Property="Foreground" Value="{StaticResource BrushWhiteSmoke}" />
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="FontSize" Value="11" />
<Setter Property="Padding" Value="7" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
<Style TargetType="{x:Type Rectangle}" x:Key="formBackgroundRectangleStyle">
<Setter Property="Fill" Value="{StaticResource BrushABCLight}" />
</Style>
<Style TargetType="{x:Type Border}" x:Key="formTitleBorderStyle">
<Setter Property="BorderBrush" Value="{StaticResource BrushBlack}" />
<Setter Property="BorderThickness" Value="0,0,0,2" />
</Style>
</ControlTemplate.Resources>
<AdornerDecorator d:DesignWidth="640" d:DesignHeight="480">
<Grid Width="Auto" Height="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Left" Margin="0" VerticalAlignment="Top" FontFamily="Arial" FontSize="18.667" Foreground="#FFE0E0E0" Text="{TemplateBinding Title}" TextWrapping="Wrap" Panel.ZIndex="2" Visibility="Collapsed"/>
<Path Fill="Black" Stretch="Fill" Stroke="{x:Null}" Margin="0" VerticalAlignment="Stretch" Height="Auto" Grid.Column="1" Grid.Row="0" Data="M0.5,0.5 L39.5,39.5 0.5,39.5 z"/>
<Border Background="Black" Margin="0" VerticalAlignment="Stretch" Height="Auto" Grid.Row="0" CornerRadius="10,0,0,0"/>
<!-- <Rectangle Fill="Black" Stroke="Black" Margin="0" VerticalAlignment="Stretch" Height="Auto" Grid.Row="0"/> -->
<Rectangle Stroke="{x:Null}" Margin="0" Height="Auto" Opacity="0.5" Grid.ColumnSpan="2" Grid.Row="3" Grid.RowSpan="1">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF222222" Offset="0"/>
<GradientStop Color="#FFB3B3B3" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Fill="Black" Stroke="Black" Margin="0" Grid.ColumnSpan="2" Grid.Row="1"/>
<Rectangle Fill="{TemplateBinding Background}" Stroke="Black" Margin="0" Height="Auto" Panel.ZIndex="-7" Grid.ColumnSpan="2" Grid.Row="2" Grid.RowSpan="1"/>
<Border x:Name="bdr" Style="{StaticResource formOuterBorderStyle}" Margin="0" Grid.ColumnSpan="2" Grid.RowSpan="3" d:LayoutOverrides="Width, Height" d:IsHidden="True" Visibility="Collapsed"/>
<Grid Margin="3" Grid.ColumnSpan="2" Grid.RowSpan="3">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="77" />
<RowDefinition MinHeight="400" />
</Grid.RowDefinitions>
<Border Style="{StaticResource formTitleBorderStyle}" BorderBrush="{x:Null}">
<StackPanel Margin="0">
<TextBlock Text="{Binding ViewModelFriendlyName}" Style="{StaticResource formTitleStyle}" />
<TextBlock Margin="11,0,0,0" Text="{Binding BreadcrumbTrail}" Style="{StaticResource formBreadcrumbStyle}" />
</StackPanel>
</Border>
<Rectangle Grid.Row="1" Style="{StaticResource formBackgroundRectangleStyle}" Visibility="Collapsed" />
<!--Put the form below here-->
<ContentPresenter x:Name="ContentPresenterX" Grid.Row="1" Margin="0" />
<!--Put the form above here-->
</Grid>
</Grid>
</AdornerDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I guess I really just want to know why I now have to tell the control to use the contentpresenter to present the content, when previously it know that is what I wanted, and also how I do it.
Any thoughts?
Cory
Added Content={TemplateBinding Property=Content} to ContentPresenter.
MSDN Forum post regarding this issue suggested adding the ContentPropertyAttribute setter to the controls codebehind, but I could not get that to work.
Cory

Resources