how to use Style.Triggers for Canvas in WPF - wpf

I want to make a simple effect for a canvas by this code, but it doesn't work.
<Canvas.Style>
<Style>
<Setter Property="Canvas.Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="Canvas.IsMouseOver" Value="True">
<Setter Property="Canvas.Background" Value="LightSkyBlue">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Canvas.Style>

Your <Style> element is missing a TargetType. Because controls can be made up of multiple controls you can use TargetType to target different control types and doing so will also give you contextual intellisense for the children Elements.
<Canvas HorizontalAlignment="Left" Height="100" Margin="215,128,0,0" VerticalAlignment="Top" Width="100">
<Canvas.Style>
<Style TargetType="Canvas">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Canvas.Background" Value="LightSkyBlue">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Canvas.Style>
</Canvas>
I feel like CSS really did a great job at making styling easy so it's a bummer that WPF has to be so esoteric.

Related

Change style of a child control on MouseOver in WPF

I have a custom control that holds two Rectangles and several TextBoxes. I wish to change the background color of the Rectangle on MouseOver.
I add trigger as following:
<Rectangle
Grid.Column="1"
Fill="#FF383838"
Grid.ColumnSpan="3"
Margin="0,4,4,4">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#FF383838" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="#FF575757" />
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
But since rectangle is part of my control, I assume the event is not firing.
Setting a property via XAML will be applied over the style properties that you try to set. To fix this, remove Fill=#FF383838 so you should have:
<Rectangle Grid.Column="1"
Grid.ColumnSpan="3"
Margin="0,4,4,4">
//... rest of code here
Try this code:
<Window.Resources>
<Style TargetType="Rectangle" x:Key="test">
<Setter Property="Fill" Value="#FF383838" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="#FF575757" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Rectangle Style="{StaticResource test}" />

why this style is not working in wpf

I have a style for button as follow:
<Style TargetType="Button" x:Key="BlackButton">
<Setter Property="Background" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="red" />
</Trigger>
</ControlTemplate.Triggers>
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and a button on which is defined as follow:
<Button Canvas.Left="19" Canvas.Top="520" Height="34" Width="107"
Style="{StaticResource BlackButton}" />
But when I run application, I can not see the button. Its background set to none.
If I change the style as follow:
<Style TargetType="Button" x:Key="BlackButton">
<Setter Property="Background" Value="Black"/>
</Style>
(Removing the template) then the button is shown but its background is not changing.
What is wrong with this xaml code?
You've overridden the template of your control in order to set the MouseOver trigger. That means your control template is otherwise empty - and so nothing is drawn for your button.
You can fix that by moving your triggers to the style itself, like this:
<Style TargetType="Button" x:Key="BlackButton">
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="red" />
</Trigger>
</Style.Triggers>
</Style>
However, what you're likely to run into now is that the button's built-in MouseOver animation will override your red background. You'll see a flash of red, followed by a transition to the default Windows colour. One way to fix that thoroughly is to take a full copy of the default Button template (using Expression Blend is the easiest way to do this) and remove the animations from it.
Well your ControlTemplate is simply empty, although you have a ControlPresenter in it. But since its Content property is not set, it's also empty. To have a Background you will have to add a Border.
<Style TargetType="Button" x:Key="BlackButton">
<Setter Property="Background" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="red" />
</Trigger>
</ControlTemplate.Triggers>
<Border Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This should show you something.

WPF: the style of control does not work unless the control template created for style

It almost gets me mad in recent days. I have a textbox and the style in xaml file.
But the style without a control template cannot take effect on textbox. Whereas, a control template works, but control template seems to overwrite the textbox totally, the default behaviors loses of textbox such as editing, inputing or selecting...
Here is content of xaml with the control template:
<Style TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Name="tbBorder" Background="White" BorderThickness="0.6" BorderBrush="#B9B9B9">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And here is the simple style which does not work at all,
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
</Style.Triggers>
</Style>
Thanks!
update: the entire textbox's code snipt:
<TextBox Height="23" HorizontalAlignment="Left" Margin="114,53,0,0" Name="textBox1" VerticalAlignment="Top" Width="150" Text="{Binding Path=TraderAccount, Mode=OneWayToSource, NotifyOnValidationError=True}" BorderBrush="#FFB9B9B9" BorderThickness="1" >
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The style setter is working for me but the issue I see is that the controls animations are animating away the style that's just been set.
You may want to extract the original control template and redefine that rather than completely redefining it. As far as I know The textbox control is more complex than just a border with a content presenter (I've never extracted the control template for it though!) and its likely to have a couple of borders that work to give it all it's states etc
You can use Blend to do this - in the absence of Blend there is the MSDN resource for control templates and styles:
http://msdn.microsoft.com/en-us/library/aa970773.aspx
Edit:
For starters it looks to me like you are missing the content 'PART' in your redefined template
<ScrollViewer Margin="0" x:Name="PART_ContentHost" />
Edit 2:
You are saying it doesn't work... this works for me on WPF using .NET Framework 4.0 - I changed the border colour to 'Red' instead to make sure I could see the effect and it definitely works, aside from the red fading immediately because the controls visual state is changed by the Visual State Manager (which is why you need to edit the control template and change the visual states)
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
When you hover over the box, you get a red border which immediately fades
Does this XAML not work for you at all??
You did not post TextBox code but I assume (it happened to me too) that you simply forgot to set BorderThickness of your textbox:
<TextBox BorderThickness="4">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Your style does work, set a property like Background in your style without the template and you will see that it does get applied. However, like someone else mentioned, the reason you do not see any changes is because of animation in the default WPF control template for TextBox (Animation values always take precedence over local values, setters and triggers). When you redefine the control template, those animations are no longer there and so your example works. What you could do is take the default TextBox template and modify it to suit your purposes (can be found here: http://msdn.microsoft.com/en-us/library/cc645061%28VS.95%29.aspx).

WPF : Chainging another control's property in some control's Trigger

Here's my textblock.
<Image x:Name:imgAnother/>
<TextBlock>
this is my text block
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="TextDecorations" Value="None"/>
<Style.Triggers>
<Trigger Property="TextBlock.IsMouseOver" Value="True">
<Setter Property="Foreground" Value="RoyalBlue"/>
<!--I like to insert a code at here that changes another control's property...-->
</Trigger>
<Trigger Property="TextBlock.IsMouseOver" Value="False">
<Setter Property="Foreground" Value="#FF808080"/>
<!--..and this line too.-->
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
I like to make a xaml code which can change another control's proerpty, like "imgAnother".
how can i do that?
You must aggregate the source and the target in some way.
You may create either a custom control containing both the hyperlink/textblock and the image. That's the preferred way if you have several blocks that behaves in such example.
If you don't like this. You may create a "temporary" anonymous control as follows:
<ControlTemplate x:Key="myCtl" TargetType="ContentControl">
<StackPanel>
<Image x:Name="img"/>
<ContentPresenter x:Name="ctr" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger SourceName="ctr" Property="IsMouseOver" Value="True">
<Setter TargetName="ctr" Property="Foreground" Value="RoyalBlue"/>
<!--I like to insert a code at here that changes another control's property...-->
</Trigger>
<Trigger SourceName="ctr" Property="IsMouseOver" Value="False">
<Setter TargetName="ctr" Property="Foreground" Value="#FF808080"/>
<!--..and this line too.-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
The above xaml will reside in your Window's resources.
NOTE: it's much like a track to follow, than a fully functional snippet!
In the body, you may refer the control in such manner:
<ContentControl Template="{StaticResource myCtl}" Content="this is my text block" />
Hope it helps.

'Graying Out' a WPF button image?

I have a simple Button control that contains an Image object as its content. I want so set the Image opacity to 0.5 when the Button is disabled to provide an additional visual cue as to the Button status.
What is the simplest way to accomplish that result in XAML? Thanks for your help.
Use a trigger in the Image style. (It would be more natural to put it in the Button style, but the Button style can't easily affect the Image for annoying technical reasons. It could be done in the Button's ControlTemplate but that's overkill for what you want here.)
<Button>
<Image Source="something.png">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
Note we are taking advantage here of the fact that the Image will be disabled when the Button is disabled, so we can trigger directly on the Image's own IsEnabled property. In other cases, the Button property we want to trigger on might not be inherited by the Image; in that case, we'd need to use a DataTrigger with the FindAncestor RelativeSource to bind to the containing button.
If you want something more generic, put this in your resources section for your window or UserControl .
<UserControl.Resources>
<Style x:Key="ImageEnabled" TargetType="Image">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.25"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
And in the actual button just do this
<Button>
<Image Source="{StaticResource LinkImage}" Style="{StaticResource ImageEnabled}"/>
</Button>
Here's a more generic style you can apply:
<Style TargetType="Button">
<Style.Resources>
<Style TargetType="Image">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
If you want the entire button greyed out, styling the button itself has worked for me. It seems to grey out all button content.
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value=".75"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
previous solutions only change opacity and not the color of the image, to gray out an image one need to convert the image to grayscale as follow. I did it for a toggleButton but the same method can be used on a button.
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content">
<Setter.Value>
<Image
RenderOptions.BitmapScalingMode="HighQuality"
RenderOptions.EdgeMode="Aliased"
Source="/Resources/imageForButton.png"
Stretch="UniformToFill" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image
RenderOptions.BitmapScalingMode="HighQuality"
RenderOptions.EdgeMode="Aliased"
Stretch="UniformToFill">
<Image.Source>
<FormatConvertedBitmap
x:Name="myImageFormat"
DestinationFormat="Gray8"
Source="/Resources/imageForButton.png" />
</Image.Source>
</Image>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>

Resources