I have the following button style that has a cross in it and is used for a close button on a TabItem
<Button Grid.Column="2"
Width="15"
Height="15"
HorizontalAlignment="Center"
VerticalAlignment="Center"
DockPanel.Dock="Right"
AttachedCommand:CommandBehavior.Event="Click"
AttachedCommand:CommandBehavior.Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CloseWorkspaceCommand}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<Path x:Name="ButtonPath"
Margin="3"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,0 L1,1 M0,1 L1,0"
SnapsToDevicePixels="True"
Stretch="Uniform"
Stroke="{DynamicResource CloseButtonStroke}"
StrokeEndLineCap="Flat"
StrokeStartLineCap="Flat"
StrokeThickness="2"/>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"
Value="false" />
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"
Value="false" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Visibility" Value="Hidden" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Hidden" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background"
Value="{DynamicResource CloseButtonBackgroundHighlighted}" />
<Setter TargetName="ButtonPath"
Property="Stroke"
Value="{DynamicResource CloseButtonStrokeHighlighted}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background"
Value="{DynamicResource CloseButtonBackgroundPressed}" />
<Setter TargetName="ButtonPath"
Property="Stroke"
Value="{DynamicResource CloseButtonStroke}" />
<Setter TargetName="ButtonPath"
Property="Margin"
Value="2.5,2.5,1.5,1.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
This produces
I want to add a CheckButton styled to show a pin next to the close button like VS2012. I can do this no problem, but I want to place the CheckBox inside the same button template above so I get highlighting when the mouse is over the area. The problem is the button above contains the Path that draws the 'X'.
Is there a was I can make the button style above generic so I can include either the 'X' Path or the CheckBox, without replicating all the trigger stuff?
Thanks for your time.
I would approach this by creating my button class like ToolBarButton below and have a dependency property ButtonType. I will set ButtonType on the ToolBarButton.
public enum ButtonType
{
Close =0,
Pin
}
public class ToolBarButton : Button
{
public ButtonType ButtonType
{
get { return (ButtonType)this.GetValue(ButtonTypeProperty); }
set { this.SetValue(ButtonTypeProperty, value); }
}
public static readonly DependencyProperty ButtonTypeProperty = DependencyProperty.Register(
"ButtonType", typeof(ButtonType), typeof(ToolBarButton), new PropertyMetadata(ButtonType.Close));
}
in xaml:
<local:ToolBarButton ButtonType="Pin"/>
Then I will add the trigger in style to check for buttontype and apply the controltemplate containing checkbox
<Style.Triggers>
<Trigger Property="ButtonType" Value="Pin">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<CheckBox/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
Related
I'm kinda new to WPF/XAML
I have this Button that holds a stack panel which is having an Image and a Textbox Control to it.
I have styled the button in a StaticResource
How can I achieve an image change on MouseOver?
I have accomplished changing the Background color, and the Foreground color (text) to change on mouseover, but I can't get the image change to work
This is my Button:
<Button Style="{StaticResource mainMenuHomeBtn}">
<StackPanel
Orientation="Horizontal"
HorizontalAlignment="Left">
<Image Name="hjemImage" Margin="5" Height="30" Source="/Images/fal-home-lg-alt.png"/>
<TextBlock Margin="10" VerticalAlignment="Center" Text="Hjem"/>
</StackPanel>
</Button>
And this is my Button Styling:
<Style x:Key="mainMenuHomeBtn" TargetType="{x:Type Button}">
<Setter Property="Width" Value="auto"/>
<Setter Property="Height" Value="auto"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Padding" Value="-2"/>
<Setter Property="Foreground" Value="#e3e3e3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderBrush="#cccccc" BorderThickness="0">
<ContentPresenter HorizontalAlignment="Left"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="#696969"/>
<Setter Property="Background" Value="#d9d9d9"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#e3e3e3"/>
</Trigger>
</Style.Triggers>
</Style>
Your Style/ControlTemplate doesn't know anything about the StackPanel that happens to be in the element that is currently set as the Content of the Button element that the Style is currently applied to.
You could move the contents to the template and use a trigger so change the Source of the Image element in the template:
<Style x:Key="mainMenuHomeBtn" TargetType="{x:Type Button}">
<Setter Property="Width" Value="auto"/>
<Setter Property="Height" Value="auto"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Padding" Value="-2"/>
<Setter Property="Foreground" Value="#e3e3e3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderBrush="#cccccc" BorderThickness="0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Image Name="hjemImage" Margin="5" Height="30" Source="/Images/fal-home-lg-alt.png"/>
<TextBlock Margin="10" VerticalAlignment="Center" Text="Hjem"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="hjemImage" Property="Source" Value="pic.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="#696969"/>
<Setter Property="Background" Value="#d9d9d9"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#e3e3e3"/>
</Trigger>
</Style.Triggers>
</Style>
Then there is no point of setting the Content property since there is no ContentPresenter in the Style:
<Button Style="{StaticResource mainMenuHomeBtn}" />
The other option is to keep your Style as-is and add a DataTrigger that binds to the IsMouseOver property of the Button to an element in the content:
<Button Style="{StaticResource mainMenuHomeBtn}">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left">
<Image Name="hjemImage" Margin="5" Height="30">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="/Images/fal-home-lg-alt.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=Button}}"
Value="True">
<Setter Property="Source" Value="pic.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Margin="10" VerticalAlignment="Center" Text="Hjem"/>
</StackPanel>
</Button>
I'm trying to create a DataTemplate for Items in a ListView which is in itself not a problem when I'm using TextBlocks.
When selecting an item in the ListView, it is highlighted as expected with a darker background and the TextBlocks have a white foreground.
However, when I add a ComboBox to the DataTemplate and when a row is highlighted, the ComboBox's forground remains black whether it's selected or not.
I am not applying any styles to ComboBoxes and other than the SelectedValue and ItemSource properties, I'm not doing anything else with the ComboBox.
Using the LivePropertyExplorer I can only see that the Foreground is "overriden" but cannot see where.
Help would be greatly appreciated!
<ListView DockPanel.Dock="Bottom"
BorderThickness="0,1,0,0"
Padding="3"
BorderBrush="LightGray"
MinHeight="150"
MaxHeight="150"
ItemContainerStyle="{StaticResource ListViewItemStyle25}">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel LastChildFill="False">
<DockPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize"
Value="14" />
<Setter Property="Background"
Value="Transparent" />
</Style>
</DockPanel.Resources>
<ComboBox BorderThickness="1"
Background="Transparent"
MinWidth="120"
MaxWidth="120"
FontSize="14"
IsSynchronizedWithCurrentItem="False"
SelectedValue="{Binding IResourceTravelDocument_TravelDocumentType}">
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsPrimary, ElementName=userControl}"
Value="True">
<Setter Property="ItemsSource"
Value="{Binding DataContext.IResourceTravelDocumentsModuleViewModel_ResourceTravelDocumentTypes_Primary,
ElementName=userControl}" />
</DataTrigger>
<DataTrigger Binding="{Binding IsPrimary, ElementName=userControl}"
Value="False">
<Setter Property="ItemsSource"
Value="{Binding DataContext.IResourceTravelDocumentsModuleViewModel_ResourceTravelDocumentTypes_Supplementary,
ElementName=userControl}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Style x:Key="ListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="VerticalContentAlignment"
Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
<Setter Property="Padding"
Value="2,0,0,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<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="ItemsControl.AlternationIndex"
Value="0">
<Setter Property="Background"
Value="White"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex"
Value="1">
<Setter Property="Background"
Value="WhiteSmoke"></Setter>
</Trigger>
<Trigger Property="IsSelected"
Value="true">
<Setter Property="Background"
TargetName="Bd"
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected"
Value="true" />
<Condition Property="Selector.IsSelectionActive"
Value="false" />
</MultiTrigger.Conditions>
<Setter Property="Background"
TargetName="Bd"
Value="RoyalBlue" />
<Setter Property="Foreground"
Value="AliceBlue" />
</MultiTrigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The ComboBox has its own Template and doesn't inherit the Background and Foreground properties from the parent ListViewItem by default.
You can add another DataTrigger to the ComboBox style that binds to the ListViewItem though:
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="true">
<Setter Property="Foreground" Value="AliceBlue" />
</DataTrigger>
<DataTrigger Binding="{Binding IsPrimary, ElementName=userControl}" Value="True">
<Setter Property="ItemsSource" Value="{Binding DataContext.IResourceTravelDocumentsModuleViewModel_ResourceTravelDocumentTypes_Primary, ElementName=userControl}" />
</DataTrigger>
<DataTrigger Binding="{Binding IsPrimary, ElementName=userControl}" Value="False">
<Setter Property="ItemsSource" Value="{Binding DataContext.IResourceTravelDocumentsModuleViewModel_ResourceTravelDocumentTypes_Supplementary, ElementName=userControl}" />
</DataTrigger>
</Style.Triggers>
</Style>
I have the below code where I'm trying to change the background color of the button when its disabled. But it still stays at the same background color as it is when its enabled. Its not changing though the button does get disabled. Any help would be much appreciated.
<Button Content="Install" Command="{Binding InstallCommand}" Margin="150,30,30,22" Width="118" FontSize="18" FontWeight="Bold" FontFamily="Segoe UI Light" FontStretch="ExtraExpanded">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#FF4F4F4F"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="1"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="Goldenrod"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding InstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Value="">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Background" Value="{DynamicResource windowBGBrushBusinessDateChanged}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I found that in your trigger you are not checking the value .Change your trigger as below.
<Style.Triggers>
<DataTrigger Binding="{Binding InstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Value="False">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Background" Value="{DynamicResource windowBGBrushBusinessDateChanged}"/>
</DataTrigger>
</Style.Triggers>
You can change the disabled button background by changing the control template of button like below,
<Window.Resources>
<Style x:Key="MyButton2" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Background" Value="MediumAquamarine" />
<Setter Property="Foreground" Value="MediumBlue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter x:Name="MyContentPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Green" />
<Setter Property="Foreground" Value="DeepPink" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button x:Name="disabledButton"
Width="100"
Height="100"
Content="Button State"
IsEnabled="False"
Style="{StaticResource MyButton2}" />
</Grid>
I am trying to define a Style that could be used where Button holds a TextBlock as its Content and when Button has IsEnabled=False I want to set TextBlock's Foregroung color.
<Button Style="{StaticResource TransparentButtonStyle}"
IsEnabled="{Binding IsAllowed}">
<TextBlock Text="Click Me"
Style="{StaticResource HyperLinkStyle}">
</TextBlock>
</Button>
<Style x:Key="TransparentButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="Transparent">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="HyperLinkStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="Blue" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Foreground" Value="LightBlue" />
<Setter Property="TextDecorations" Value="Underline" />
</Trigger>
</Style.Triggers>
</Style>
Can I modify the TextBlock's Style to grab the parent Button's IsEnabled value somehow to be able to set the Foreground color ?
you can just add <Trigger Property="IsEnabled" Value="False"> to your HyperLinkStyle, but I recommend you to create LinkButtonStyle instead, so you final markup fill be much cleaner:
<Button Content="Link text" Style="{StaticResource LinkButtonStyle}" />
this just makes your views much cleaner...
here's my LinkButton template:
<Style x:Key="LinkButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="{StaticResource LinkButtonText}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock x:Name="ContentPresenter" Background="{TemplateBinding Background}"
Text="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ContentPresenter" Property="Foreground" Value="{DynamicResource LinkButtonDisabled}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsEnabled" Value="True" />
</MultiTrigger.Conditions>
<Setter TargetName="ContentPresenter" Property="TextDecorations" Value="Underline"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If you want to get to Button you can use DataTrigger with RalativeSource binding
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!-- Setters -->
</Trigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=IsEnabled}" Value="False">
<!-- Setters -->
</DataTrigger>
</Style.Triggers>
but if you want to make your Style independent of what is the parent then normal Trigger on IsEnabled property should work just as good
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!-- Setters -->
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<!-- Setters -->
</Trigger>
</Style.Triggers>
normal Trigger should work because IsEnabled value is influenced by UIElement.IsEnabledCore which
Gets a value that becomes the return value of IsEnabled in derived classes
...
The default implementation of this property caches the value and also calculates whether the parent element of this element is enabled. (If the parent is not enabled, the child element cannot be effectively enabled in practical user interface (UI).)
so basically if parent Button is disabled child TextBlock will be disabled as well
I'm implementing a search textbox; could you please help me with binding to TextBox.Tag?
Style
<Style x:Key="SearchTextBox" TargetType="{x:Type TextBox}">
<Style.Resources>
<VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" Foreground="{StaticResource SearchTextBox.Foreground}" FontSize="{StaticResource SearchTextBox.FontSize}"/>
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Setter Property="FontSize" Value="{StaticResource SearchTextBox.FontSize}" />
<Setter Property="Foreground" Value="{StaticResource SearchTextBox.TextForeground}" />
<Setter Property="MinWidth" Value="200" />
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
Usage
<TextBox Style="{StaticResource SearchTextBox}" Tag="Search templates" />
How can I get the binding to work?
This article here is extremely similar to yours: WPF Bind to parent property from within nested element using style
Though, it doesn't really give a code sample, so here's some xaml you can use as an alternative to your current approach.
<Style x:Key="SearchTextBox" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
<Style.Setters>
<Setter Property="Tag" Value=""/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<TextBlock x:Name="textBlock" Opacity="0.345" Text="{TemplateBinding Tag}" TextWrapping="Wrap" Visibility="Hidden" />
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="False" />
<Condition Property="Text" Value="" />
</MultiTrigger.Conditions>
<Setter Property="Visibility" TargetName="textBlock" Value="Visible" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
And you'll still write your textbox code the same way you already had it:
<TextBox Style="{StaticResource SearchTextBox}" Tag="Search templates" />