I have wpf app with button, that should reflect two states - enabled/disabled.
The button have image as its content:
<Button Name="FindButton" Style="{StaticResource TextEditorToolbarButtonStyle}"
Command="FindButtonCommand"
Margin="2,0,10,0">
<Image Name="FindSvgViewbox" Style="{StaticResource TextEditorToolbarIconStylePng}"
Source="/Img/png/enabled/find.png"/>
</Button>
So in some cases button will be disabled, and those image source will changed like this:
FindSvgViewbox.Source = new BitmapImage(new Uri(disabledImagePath));
This works, but image actualy change only after i click on some other control like textboxt or other button, so there is some kind of lag or delay.
What can cause the problem?
EDIT:
Here is style for button:
<Style x:Key="TextEditorToolbarButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Width" Value="30"></Setter>
<Setter Property="Height" Value="30"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="Background" Value="#F1F1F1"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#C5C5C5"/>
</Trigger>
</Style.Triggers>
</Style>
The image source changed in CanExecuteChanged handler for button:
FindButtonCommand = new RelayCommand(DoFind, o => FindCanExecute);
FindButtonCommand .CanExecuteChanged += (sender, args) =>
{
AppUtils.ChangeIconSource(FindButton, FindSvgViewbox);
};
If image source is only depends on enabled/disabled state of button (which is IsEnabled property), you can control image source value with pure XAML. Your TextEditorToolbarIconStylePng style should be like this:
<Style x:Key="TextEditorToolbarIconStylePng" TargetType="Image">
<Setter Property="Source" Value="/Img/png/enabled/find.png" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Source" Value="/Img/png/enabled/findDisabled.png" />
</Trigger>
</Style.Triggers>
</Style>
Note that initial Source value should be assigned from style's Setter rather than from Image element directly, and of course you shouldn't edit Source value from code.
Also note that this style uses image's IsEnabled property, which is by default inherited from button's IsEnabled property (controlled by command), unless you will manually edit image's property.
Related
I have a TextBox in WPF and I'm trying to make the border color change when the mouse hovers over the TextBox. Based on my experience with other elements in WPF, I need to insert a ControlTemplate value with TemplateBinding to the values I am trying to dynamically change. However, when I apply this, the box becomes uneditable (and the text disappears). If I remove the Template setter, the box becomes editable again, but the custom BorderBrush triggers do not work.
Here is the Style:
<Style x:Key="TextBoxBase" TargetType="TextBox">
<Setter Property="FontSize" Value="30"/>
<Setter Property="Background" Value="{StaticResource BrushLightGrey}"/>
<Setter Property="Foreground" Value="{StaticResource BrushNormalText}"/>
<Setter Property="IsReadOnly" Value="False"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderBrush="{TemplateBinding BorderBrush}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource BrushBlue}"/>
</Trigger>
</Style.Triggers>
<Style.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="5"/>
</Style>
</Style.Resources>
</Style>
Any suggestions or help is appreciated. Thanks.
You missed out the critical part:
<ScrollViewer Margin="0"
x:Name="PART_ContentHost" />
This is what hosts the text.
See
https://learn.microsoft.com/en-us/dotnet/framework/wpf/controls/textbox-styles-and-templates
TextBox Parts
The following table lists the named parts for the TextBox control.
TEXTBOX PARTS
Part Type Description
PART_ContentHost FrameworkElement A visual element that can contain a FrameworkElement. The text of the TextBox is displayed in this element.
I start to learn WPF and there is something that is still unclear for me:
i created new Style for button:
<!-- no border button style -->
<Style x:Key="NoBorderButton" TargetType="Button">
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Style.Triggers>
<Trigger Property="Control.IsMouseOver" Value="true">
<Setter Property="Control.FontSize" Value="18" />
</Trigger>
<Trigger Property="Control.IsMouseOver" Value="true" >
<Setter Property="Foreground" Value="LightSkyBlue" />
</Trigger>
<Trigger Property="Control.IsMouseOver" Value="false" >
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
So this is my button:
<Button Content="Button" Style="{StaticResource NoBorderButton}">
</Button>
Now after search for solution to remove all the border i found this template that need to be add to the button:
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Button.Template>
So i have several questions:
What this template doing ?
Why i cannot add it the the style i created inside my Windows.Resources ?
I'm going to attempt to answer your questions directly, however there is much that can be discussed here.
What this template doing?
All controls have some kind of default template, a pre-defined look and feel of what the control looks like.
The Template is overriding the default look and feel for your Button. What you are effectively doing is completely starting afresh a new template for a button.
So for example, you can define a new template for what a button would look like. It can be a TextBlock inside an Ellipse for example. Instead of the default button template.
It's hard to put into words, but I think I explained that well enough.
Why i cannot add it the the style i created inside my Windows.Resources?
You can:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
...
</ControlTemplate>
</Setter.Value>
</Setter>
I just started getting used to WPF using Blend for Visual Studio. I created previous programs with the standart Windows Forms and now want to get to something more modern.
But I already encountered a main problem after like 5 Minutes.
I added a button with an background image with a transperancy. That worked like a charm, but the problem is that, when I run the application, the button always gets blue when the Mouse hovers it. I do not want this blue effect but can't find the option to disable it in Blend.
Hope someone can help me with this stupid question, Windows Forms was a little
What you're describing is the default state behavior for the button. You would have to create a custom template or style to change it. Example:
<Button Content="Button">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Black"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I am demonstrating two properties changes here: Background & Foreground. You may have as many as you want and change them to whatever value you wish. If you don't want any changes, simply remove Style.Triggers or a particular property within it.
Here's a demo for you, since you're new:
Here's the Resource Dictionary way:
Create a Resource Dictionary and add a style to it:
<Style x:Key="CustomButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Black"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
Place this in your App.xaml or wherever you merge your resource dictionaries:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ButtonStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Then simply specify the style for your button:
Style="{StaticResource CustomButtonStyle}"
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.
At the code below, when a mouse is over the grid, the grid's Background is expected to be red, but it isn't executed as expected.
<Grid>
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
However, if I added the Setter to make the Background green, it would be executed properly.
<Grid>
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Setter Property="Background" Value="Green"/><!-- at the former, added code-->
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
I don't know why it is, but guess that there is a precedence for setting the Background, causing the issue. Here is Dependency Property Value Precedence from MSDN, and I understand the precedence of of that reference, but I cannot link this issue to the precedence(MSDN).
Additionally, at above the code snippets, if the Grid is replaced with a Button, both these code will not be executed as expected.
UPDATED: Adding Button case about this issue
<Button>
<Button.Style >
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
The problem is your Grid has a null background, so it is not visible for mouse hit testing. If you set the Background to Transparent, then it will be hit-testable like when you set it to green.
More information can be found here.
I tried your Button and the Background is initialized to Transparent properly. The Red value is only shown for a fraction of a second. This is because in the Aero theme (I'm on Windows 7) the Button's ControlTemplate uses a custom chrome to provide animated state transitions (i.e. when hovering etc). This custom chrome element uses internal brushes and it ignores the Background property.
This has nothing to do with property precedence. For the Grid, it's simply a matter of your Grid not being hit-testable. So it's IsMouseOver will not be set to true, unless it has a non-null background (or a child which renders something).
You can see the Precedence in action here:
<Grid Background="Blue">
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
In the above, the Grid will always be Blue as that has the highest precedence (i.e. local or #3). While Red (#6) takes precedence over Green (#8).
In the case of the Button, you have something like this:
<Button Background="Blue">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border" Background="{TemplateBinding Background}">
<ContentPresenter />
</Border >
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
In this case, there are two Background properties in play: the Button and the Border in the control template. The Button's Background property is used by the Border by default, but when the mouse is hovering it uses a Red brush. At that point, it doesn't matter what the value of the Button's Background property is set to.