WPF - ListBox ignores Style When ItemsSource is bound - wpf

I have created styled a ListBox in WPF so that it is rendered as a checkbox list.
When I populate the ListBox's items manually, the styling works perfectly. However, when I instead bind the ItemsSource of the ListBox to a static resource (an ItemsControl containing the required items), the styling is completely dropped.
Here's the style:
<Style x:Key="CheckBoxListStyle" TargetType="ListBox">
<Style.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<ContentPresenter
Grid.Column="1"
Margin="2,0,0,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
</Style>
Here's the code for the ListBox that shows the style correctly:
<ListBox x:Name="ColumnsList"
Grid.Column="0"
Grid.Row="0"
Style="{StaticResource CheckBoxListStyle}"
BorderThickness="1">
<ListBox.Items>
<ListBoxItem>Test</ListBoxItem>
<ListBoxItem>Test2</ListBoxItem>
<ListBoxItem>Test3</ListBoxItem>
</ListBox.Items>
</ListBox>
Here's the code for the ListBox that ignores the style:
<ListBox x:Name="ColumnsList2"
Grid.Column="0"
Grid.Row="0"
Style="{StaticResource CheckBoxListStyle}"
BorderThickness="1"
ItemsSource="{Binding Source={StaticResource Test1}, Path=Items}">
</ListBox>
Hoping someone can help - I'm pretty new to all this and have tried everything I can think of, but everything I've read leads me to believe that setting ItemsSource should have the same outcome as setting the items manually, so I can't see any reason why this would not work.
Thanks,
AT

Change the Style.Resources to setting the ItemContainerStyle property and it should work like a charm.
<Style x:Key="CheckBoxListStyle" TargetType="ListBox">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<ContentPresenter
Grid.Column="1"
Margin="2,0,0,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
</Style>
In older versions (before SP1), when you define Styles in Style, one of those style will be ignored. Alternatively, you can set the Resources of Style in the parent resources..
Hope this helps!

This is because your TargetType in the CheckListBoxStyle is targetting a ListBoxItem, but when you set the ItemSource property of the ListBox you are binding to a list of other elements (ints for example). This means your target type should be int instead of ListBoxItem.
Alternatively do not specify a target type.

Related

WPF Style ListBox with ItemStyle and DataTemplate

I'm using WPF 4.5.2 and .Net 4.7.2
My base style looks like this
<Style x:Key="MyListBoxItem" TargetType="{x:Type ListBoxItem}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderBrush="Black" BorderThickness="1,0,1,1">
<TextBox Text="{Binding MyText}" />
</Border>
<Border Grid.Column="1" BorderBrush="Black" BorderThickness="0,0,1,1">
<ContentPresenter />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
furthermore, there are several DataTemplates looking something like this
<DataTemplate x:Key="SomeDataTemplate">
<TextBox Text="{Binding SomeString}" x:Name="txtContent" Style="{DynamicResource MyStyle}" />
</DataTemplate>
I'm using a DataTemplateSelector class. Everything is recognized correctly, so there isn't any issue in terms of setting the ItemContainerStyle or the DataTemplateSelector.
But the style of the TextBox in the ControlTemplate of the ListBoxItem should be changed as well as the style the TextBox in the DataTemplate.
Is that possible or do I have move the ControlTemplate entirely to the DataTemplate?
I recommend to move all data related controls, i.e. controls that bind to the item's DataContext to the DataTemplate. Then use a DataTrigger to switch between different styles that targets the TextBox.
<DataTemplate x:Key="SomeDataTemplate">
<StackPanel>
<TextBox x:Name="TxtContent"
Style="{StaticResource DefaultStyle}" />
<TextBox x:Name="OtherTxtContent"
Style="{StaticResource OtherDefaultStyle}" />
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding SomeProperty}" Value="True" >
<Setter TargetName="TxtContent" Property="Style" Value="{StaticResource AlternativeTextBoxStyle}" />
<Setter TargetName="OtherTxtContent" Property="Style" Value="{StaticResource OtherAlternativeTextBoxStyle}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

WPF DataGridTemplateColumn background color not changing on datagrid row selected

I have below WPF Toolkit DataGrid. I have created a custom column using DataGridTemplateColumn which contains a toggle button (without text).
When datagrid row is selected, toggle button background color is correctly changed with the same color as row selection but the cell's background is not changing the color, it remains white. Why?
This is the appearance of the DataGridTemplateColumn column before and after row selection.
Before:
After:
Here the code:
<UserControl.Resources>
<ResourceDictionary>
<!-- Body content datagrid cell vertical centering -->
<Style x:Key="Body_Content_DataGrid_Centering" TargetType="{x:Type dg:DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dg:DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<!-- Other Stuff -->
<dg:DataGrid x:Name="MyDg"
ItemsSource="{Binding Path=ListOfItems}"
Margin="3 5 5 5"
AutoGenerateColumns="False"
CanUserAddRows="False" CanUserResizeRows="False"
SelectionMode="Single"
SelectedItem="{Binding Path=MySelectedItem}"
ColumnWidth="*"
AlternationCount="2"
Focusable="False" SelectionUnit="FullRow"
CellStyle="{StaticResource Body_Content_DataGrid_Centering}">
<dg:DataGrid.Columns>
<dg:DataGridTemplateColumn Header="Selection" Width="Auto" CanUserResize="False">
<dg:DataGridTemplateColumn.CellStyle>
<Style TargetType="dg:DataGridCell">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</dg:DataGridTemplateColumn.CellStyle>
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ToggleButton Content="" IsChecked="{Binding Path=IsSelected}">
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel Orientation="Horizontal">
<Image MaxWidth="32" MaxHeight="32">
<Image.Style>
<Style>
<Setter Property="Image.Source" Value="/My.Graphics;component/PNG/Unchecked.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ToggleButton}}}" Value="True">
<Setter Property="Image.Source" Value="/My.Graphics;component/PNG/Checked.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<!-- <ContentPresenter Content="{TemplateBinding Content}" Margin="0,0,0,0" />-->
</StackPanel>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
Finally, I have solved it, the problem was in the style declaration for the DataGridTemplateColumn.
Despite setting toggle button background to Transparent it was not working as Raviraj suggested.
Finally the solution was to change the piece of code regarding to the DataGridTemplateColumn:
<dg:DataGridTemplateColumn.CellStyle>
<Style TargetType="dg:DataGridCell">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</dg:DataGridTemplateColumn.CellStyle>
By this one:
<dg:DataGridTemplateColumn.CellStyle>
<Style TargetType="dg:DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dg:DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</dg:DataGridTemplateColumn.CellStyle>
Doing this is working.
Below the result.
Before row selection:
After row selection:
Set the background color of your the column template to transparent.
Something like this:
<DataTemplate>
<ToggleButton Background="Transparent" Content="" IsChecked="{Binding Path=IsSelected}">

WPF apply triggers to listview items to change background

I am trying to create a sort of left menu for navigation inside the desktopapplication. My idea is to use Buttons as Listview items which should behave in this way: when i hover with the mouseover them theri background should change color (becomes darkCyan) and when i click one its background color should change persistently (to darkCyan) until i click on another button of the list. The problem is that i am using a the DataTemplate property to specify how the buttons should look like and I am tryin to apply the triggers to change the background color on the ControlTemplate of the ListView. The result is that sometimes the background color changes but the command related to the button is not fired other times the contrary. I think that I am doing the things in the wrong element of the tree view, but I don't have enough knowledge of the tree view so I am not understanding what I am doing wrong. Here is the code of the XAML in which i define the styles for the Buttons and the ListView
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:TripViewModel}">
<views:TripView />
</DataTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Height"
Value="50" />
<Setter Property="Background"
Value="#555D6F" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border>
<Grid Background="Transparent">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border BorderBrush="Transparent"
BorderThickness="0"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="DarkCyan" />
</Trigger>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Background"
Value="DarkCyan" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And here is the code in which I create the ListView
<ListView Name="MenuButtons"
ItemsSource="{Binding PageViewModels}"
Background="Transparent"
IsSynchronizedWithCurrentItem="True">
<ListView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Margin="0" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Anyone can help?
Thanks
I have solved the issue by using a ListBox instead of a ListView and setting the ItemContainer to be a button in the following way
<ListBox.ItemTemplate>
<ItemContainerTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Margin="0" />
</ItemContainerTemplate>
</ListBox.ItemTemplate>

WPF: How to show column value for a Chart.ColumnSeries?

I'm using the WPF Toolkit for a .Net 4.0 application written in C#. I have a Chart containing a Column Series bound to a dictionary. The chart works fine but I'd like to show the actual value of each column, either in a textbox below each column, in the middle of each column, or on top of each column. I've been searching for a while and haven't been able to find any information on this. I set up a style for the chart as well as the ColumnSeries, but have not made any progress yet. Any suggestions?
My Chart xaml is:
xmlns:DV="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:DVC="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
...
<Page.Resources>
<Style x:Key="MyChart" TargetType="DVC:Chart">
<Setter Property="PlotAreaStyle">
<Setter.Value>
<Style TargetType="Grid">
<Setter Property="Background" Value="#FF2D2D30" />
</Style>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="NoLegend" TargetType="DV:Legend">
<Setter Property="Visibility" Value="Hidden" />
<Setter Property="Width" Value="0" />
</Style>
<Style x:Key="ColumnSeriesStyle" TargetType="{x:Type DVC:ColumnSeries}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DVC:ColumnSeries}">
<Canvas x:Name="PlotArea" Visibility="Visible">
<TextBox Text="{Binding Path=Value.Value}" IsReadOnly="True"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
...
<DVC:Chart Name="TempChart" Style="{StaticResource MyChart}" LegendStyle="{StaticResource NoLegend}">
<DVC:Chart.Series>
<DVC:ColumnSeries IndependentValueBinding="{Binding Path=Value.Value}"
DepdendentValueBinding="{Binding Path=Value.Value}"
ToolTip="{Binding Path=Value.Value}"
Style="{StaticResource ColumnSeriesStyle}">
<DVC:ColumnSeries.DependentRangeAxis>
<DVC:LinearAxis x:Name="TempYAxis"
</DVC:ColumnSeries.DependentRangeAxis>
</DVC:Chart.Series>
</DVC:Chart>
I managed to style my ColumnSeries with this:
<Style x:Key="ColumnSeriesStyle" TargetType="{x:Type DVC:ColumnSeries}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DVC:ColumnSeries}">
<Canvas x:Name="PlotArea" Visibility="Visible">
<!-- Actual Values -->
<ListBox x:Name="ActualValueListBox" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
Background="{StaticResource WindowBackground}" Foreground="#FFBB702F" BorderBrush="#FF2D2D30" ItemsSource="{Binding}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center" FontSize="12"
Foreground="{StaticResource ValueForeground}" Background="{StaticResource ValueBackground}" Width="40"
Text="{Binding Path=Value.Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Height="20"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DVC:ColumnSeries}}, Path=ActualWidth}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

ListBox of expanders not acting like radiobuttons

I have created a listbox of expanders like this question: Expander Auto Open/Close
The solution works with content in the expanders when the listbox is the only item on the window.
But when I try to use the same code with my custom control, I'm getting this error:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'RelativeSource FindAncestor,
AncestorType='System.Windows.Controls.ListBoxItem',
AncestorLevel='1''. BindingExpression:Path=IsSelected; DataItem=null;
target element is 'Expander' (Name=''); target property is
'IsExpanded' (type 'Boolean')
I've tried adding the IsSelected Property in the ListBox.ItemContainerStyle as one poster suggested in another thread but that failed.
<ListBox Margin="5"
SelectionMode="Single"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Resources>
<Style TargetType="{x:Type Expander}">
<Setter Property="IsExpanded"
Value="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" />
</Style>
<Style TargetType="{x:Type controls:SelectionCriteriaControl}">
<Setter Property="MaxHeight"
Value="200" />
</Style>
</ListBox.Resources>
<Expander Header="Fund Family" Margin="2">
<StackPanel>
<controls:SelectionCriteriaControl DataContext="{Binding FundFamilySelectionCriteria, Mode=TwoWay}" />
</StackPanel>
</Expander>
<Expander Header="Asset Class" Margin="2">
<StackPanel>
<controls:SelectionCriteriaControl DataContext="{Binding AssetClassSelectionCriteria, Mode=TwoWay}" />
</StackPanel>
</Expander>
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<ItemsPresenter />
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter Content="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Fails miserably!!!!!
Any help appreciated :)
It's a bit of a large scenario for me to set up at the moment, but something that comes to mind to try:
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}" />
I don't think where templates are used that you can define relative sources by type.
Edit: This code worked fine: Based on your original, the TemplatedParent wasn't necessary.
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ListBox x:Name="testList" Margin="5"
SelectionMode="Single"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Resources>
<Style TargetType="{x:Type Expander}">
<Setter Property="IsExpanded"
Value="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" />
</Style>
</ListBox.Resources>
<Expander Header="Fund Family" Margin="2">
<StackPanel>
<TextBlock Text="First"/>
<TextBlock Text="Second"/>
</StackPanel>
</Expander>
<Expander Header="Asset Class" Margin="2">
<StackPanel>
<TextBlock Text="First"/>
<TextBlock Text="Second"/>
</StackPanel>
</Expander>
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<ItemsPresenter />
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter Content="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Button HorizontalAlignment="Left" Content="Test" Grid.Row="1" Width="60" Click="Button_Click"/>
</Grid>
And a quick code-behind to trigger a programmatic SelectedIndex set...
private void Button_Click(object sender, RoutedEventArgs e)
{
testList.SelectedIndex = 1;
}
Seems to work fine for me. Clicking on a list item expands, and even using the button to set it specifically by setting the selected index it expands. Something very fishy is affecting your specific scenario... :]

Resources