How do I style the ToggleButton in the Expander control WPF - c#

I'm currently trying to style the ToggleButton in the Expander control
but I can't figure out how to change it's Background color and the Foreground color.
I've currently managed to change the Text in the border but I can seem to find how to target the ToggleButton, is it under some other name?
This is what I've got so far.
<Style TargetType="Border" x:Key="RacePitBorderStyle" >
<Setter Property="Background" Value="{StaticResource BackBrush}"/>
</Style>
<DataTemplate x:Key="titleText">
<Border Style="{StaticResource RacePitBorderStyle}" Height="24">
<TextBlock Text="{Binding}"
Margin="75,0,0,0"
VerticalAlignment="Center"
Foreground="White"
FontSize="11"
FontWeight="Medium"
Width="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type Expander}},
Path=ActualWidth}"/>
</Border>
</DataTemplate>
<Style TargetType="{x:Type Expander}">
<Setter Property="HeaderTemplate" Value="{StaticResource titleText}"/>
</Style>

Related

WPF How to bind a control which is defined in a style from the element which uses the style?

I'm new to wpf and xaml,
trying to understand the basic concepts by writing a simple app using MVVM.
One thing I can't wrap my head around is
How to bind a control eg. textBox which is defined in a style to a viewModel from the control which uses this style?
Style Example (I like to bind the textBox named "SearchBox"):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type TextBox}"
x:Key="FlatSearchBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border CornerRadius="10"
Background="#353340"
Width="200" Height="40">
<Grid>
<Rectangle StrokeThickness="1"/>
<TextBox Margin="1"
Text="{TemplateBinding Text}"
BorderThickness="0"
Background="Transparent"
VerticalContentAlignment="Center"
Padding="5"
Foreground="#CFCFCF"
x:Name="SearchBox"/>
<TextBlock Grid.Column="1"
IsHitTestVisible="False"
Text="Search"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10,0,0,0"
FontSize="11"
Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=SearchBox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="Visibility" Value="Hidden"/>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Part of XAML in which the style is applied to a textBox:
<TextBox Grid.Row="2" Grid.Column="2"
VerticalAlignment="Center"
FontSize="20"
Style="{StaticResource FlatSearchBox}"
Text="{Binding CurrentFinanceModel.Value, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource currencyConverter}}"/>
The text binding should apply to the textBox named "SearchBox" in the style.
Hope the question is clear and I did not make a mistake, because it's my first question here :)
Thanks!

Trying to override textbox for combobox styling (System.windows.markup.staticresourceholder exception)

I'm new in WPF and acccording to my previous question How to make selecteditem text red and bold on trigger (in combobox) I still have a problem with making my selecteditem (but not all combobox items) text red and bold in case when its IsNotCorrect property is true. If be more concrete I have system.windows.markup.staticresourceholder exception (it seems that all converters are declared, not sure of my new style declaring and the right order for it). These are the steps I have made:
create style to override textbox for my combobox at the beginning of my xaml file:
<Style x:Key="UserDefinedStyle" TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<TextBox x:Name="PART_EditableTextBox"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Margin="3,3,23,3"
Focusable="True"
Background="Transparent"
Visibility="Hidden"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
try to apply this style on my combobox (this part is inside of another style.
<Border BorderBrush ="{Binding SelectedReason.IsNotCorrect, Converter={StaticResource DisablingBoolToColorConverter}}" BorderThickness="2">
<ComboBox x:Name="REASON_ID" DisplayMemberPath="Name" IsReadOnly="True" IsEditable="True" SelectedItem="{Binding SelectedReason, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Style"{DynamicResource UserDefinedStyle}">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem Content="{DynamicResource lang_Common_SelectItem}" IsEnabled="False"/>
<CollectionContainer Collection="{Binding Source={StaticResource StaticReasons}}"/>
<TextBox x:Name="Part_EditableTextBox">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{x:Null}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.IsNotCorrect, RelativeSource={RelativeSource AncestorType=ComboBox}}" Value="True">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
<TextBox.Style>
</TextBox>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
</Border>

How do I change a controls background on my UserControl when the item is selected

So I have this ListView which has a DataTemplate of my UserContol because I wanted a custom design for my ListView and it looks like this
<ListView x:Name="LeftMenuListView"
ItemsSource="{Binding MenuItems}"
SelectedItem="{Binding SelectedMenuItem}"
BorderThickness="0"
Width="255">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<local:MenuItemControl/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Super simple, now when an Item is selected the entire thing changes color
which I want it looks great imo
<Style TargetType="ListViewItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
Name="Border"
BorderThickness="0">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background"
Value="#444444"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But there is a border inside my usercontrol thats 10px wide with the name SmallBorder.
I want to change the color of that to green when the item is selected but I have no idea how to access that property
My UserControl
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Border Width="10"
HorizontalAlignment="Left"
x:Name="SmallBorder"/>
</Grid>
So how do I change the color of SmallBorder when an item is selected and then when it's not selected it turns transparent?
The ViewModel, which is the DataContext of you usercontrol, should expose a property like IsSelected, then you can add an style with a DataTrigger that reacts to a change in this property.
EDIT:
Declare an style for the border itself an access it as an StaticResource:
It could be placed in a ResourceDictionary, within YourUserControl.Resources or inline with the Border control declaration:
<Style TargetType={x:Type Border} x:Key=SelectedBorderStyle>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="BorderBrush" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
And then your UserControl would be:
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Border Width="10"
Style={StaticResource SelectedBorderStyle}
HorizontalAlignment="Left"/>
</Grid>
Note that now you don't need to set the name for the Border.
A Border is invisible unless there is something in it, but you could replace the Border with a Grid and use a Style with a DataTrigger that binds to the IsSelected property:
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Grid Width="10"
HorizontalAlignment="Left"
x:Name="SmallBorder">
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
</Grid>

Unable to resize StackPanel when IDataErrorInfo is triggered

When a TextBox element has an error The custom adorner doesn't resize the StackPanel the Textbox control lies in:
Using DockPanel.Bottom causes the adorner to overlap on the Textbox below.
The code I shamelessly lifted off http://hirenkhirsaria.blogspot.ie/2013/05/wpf-input-validation-using-mvvm.html:
<ControlTemplate.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
</ControlTemplate.Resources>
<DockPanel LastChildFill="true">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Border>
<AdornedElementPlaceholder Name="customAdorner">
<Border BorderBrush="#DC000C" BorderThickness="1.3" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
Sure, I could use Z Index but I don't like it.
Is there a way to cause the StackPanel to resize on error?
I was thinking of adding a ContentTemplate after each Textbox control:
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
The ContentTemplate generates an error info DataTemplate which I believe should cause the StackPanel to resize.
But I can't figure out how the binding to (Validation.Errors)[0].ErrorContent} should be done.
My terrible attempt:
<UserControl.Resources>
<DataTemplate x:Key="errorinfo">
<TextBlock>Hello World</TextBlock>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<StackPanel>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
</StackPanel>
<ContentControl >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=name, Path=(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ElementName=name, Path=(Validation.Errors)[0].ErrorContent}"> </TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
I can't reuse the datatemplate though!
My question is similar to: WPF- Validation -The validation error message goes behind the other controls because of AdornerDecorator
I just want a different solution.
Any ideas? Thanks
Adorner layers sit separate from the main rendering layers in WPF. A good way to think of an Adorner is simply as a graphical overlay layer which encompasses the shape of the Control it's element tags surround (similar to the behaviour of a Border for example).
You don't need a separate AdornerDecorator for every Control. This means the ideal solution would be to add the AdornerDecorator at the highest level possible such as your Window so that you are always guaranteed an Adorner scope.
I can't believe it! Figured it out myself :D
<UserControl.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
<DataTemplate x:Key="errortemplate">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding Path=(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
<Style x:Key="ContentControlErrorTemplate" TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
<ContentControl Style="{StaticResource ContentControlErrorTemplate}">
</ContentControl>
</StackPanel>
If you have ideas to improve it please let me know. I'm not sure how efficient it is but it works.

WPF TreeView How to make trigger for IsSelected of treeViewItem

The following code is treeview:
<TreeView BorderThickness="1,1,1,1" BorderBrush="#ffcccccc" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemTemplate="{StaticResource itemTypeTreeViewTemplate}"
ItemsSource="{Binding ItemTypes}"
ItemContainerStyle="{StaticResource treeViewItemStyle}"/>
And i set the itemTemplate to set the binding of items. Then set the ItemContainerStyle to change IsSelected style:
<Style x:Key="treeViewItemStyle" TargetType="TreeViewItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate x:Key="itemTypeTreeViewTemplate"
ItemsSource="{Binding Child}">
<DockPanel Margin="0,5,0,5">
<Button VerticalAlignment="Center"
x:Name="btn1" Width="25"
Visibility="{Binding Path=IsMouseOver,RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter }}"
Content="U" DockPanel.Dock="Right" cal:Message.Attach="[Event Click] = [Action EditItemType($dataContext)]"
Style="{StaticResource ButtonStyle1}" />
<TextBlock Margin="0,2,0,2" VerticalAlignment="Center" Text="{Binding ItemTypeName}" Foreground="#FF2e8bcc" FontSize="10" FontFamily="微软雅黑" />
</DockPanel>
</HierarchicalDataTemplate>
But the isSelected style is not work. Anybody find the key??
Instead of using a style trigger, you should override the colour key for the highlighted state. Here's the code:
<Style x:Key="treeViewItemStyle" TargetType="TreeViewItem">
<!--<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
</Style.Triggers>--><!--Remove Style.Trigger block-->
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="LightBlue"/>
</Style.Resources>
</Style>
Hope this helps. The other keys for this control are:
HighlightBrushKey - Focussed background. (Is focussed when
selected)
HighlightTextBrushKey - Focussed foreground.
InactiveSelectionHighlightBrushKey - Normal background.
InactiveSelectionHighlightTextBrushKey - Normal foreground.

Categories