Change fill property of button's path from code - wpf

I am new to WPF and I am making a WPF project for university with custom made buttons.
<Style x:Key="Button113" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Path x:Name="path" Fill="#FF8E2424" Stretch="Fill" Opacity="0.0" Stroke="{x:Null}" Data="M575.33333,304.87333 C651.33333,305.20667 651.33365,305.20699 651.33365,305.20699 620.33383,380.13463 620.16716,380.46764 620.16716,380.46764 576.16698,380.30114 576.16698,380.30114 576.16698,380.30114 575.50031,305.04016 575.33333,304.87333 575.33333,304.87333 z"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" TargetName="path" Value="DarkSlateBlue"/>
<Setter Property="Opacity" TargetName="path" Value="0.4"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and then I create the button using the style
<Button x:Name="button113" HorizontalAlignment="Right" Margin="0,0,16.25,27.416" Style="{DynamicResource Button113}" VerticalAlignment="Bottom" Width="78" Height="77.834" Content="" ToolTip="" ToolTipOpening="Button_ToolTipOpening" Click="form6_roomBtn_Click"/>
I have had some trouble making the button change color on mouse hover, but somehow I managed to do it with trigger.
Now I would like to change the background property of the button from my c# code but nothing happens. How do I access the fill property of the path from my code? (i tried using path.Fill but path is not recognized).
Thank you
Thank you

Accessing items within a ControlTemplate becomes a headache, especially if the class you are templating is not defined by you. I would suggest trying this instead:
<Style x:Key="Button113" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Path x:Name="path" Fill="{TemplateBinding Background}" Stretch="Fill" Opacity="0.0" Stroke="{x:Null}" Data="M575.33333,304.87333 C651.33333,305.20667 651.33365,305.20699 651.33365,305.20699 620.33383,380.13463 620.16716,380.46764 620.16716,380.46764 576.16698,380.30114 576.16698,380.30114 576.16698,380.30114 575.50031,305.04016 575.33333,304.87333 575.33333,304.87333 z"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" TargetName="path" Value="DarkSlateBlue"/>
<Setter Property="Opacity" TargetName="path" Value="0.4"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This binds the fill of the path to the Background property of the Button. Now you can just change the Background property at will, without having to get into the nastiness of getting stuff from inside your template.

Related

Remove ToggleButton annoying background Mouse over style

I have simple ToggleButton and when IsChecked i want to change only the text.
I want all other properties like border and background will be Transparent but it seems that i still have this background style:
<ToggleButton x:Name="changeButBorderedBlinky" Content="EDIT" Width="40" Height="40" Background="Transparent">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Content" Value="Done"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
One thing that is often annoying is some visual aspects of the default WPF controls are coded in a way so as they are not configurable. The MouseOver Background is an example (scrollbar sizes is another... grrr!!!). You can solve this though by defining your own Template for the ToggleButton and eliminate that MouseOver trigger. Here is a simple example:
<ToggleButton x:Name="changeButBorderedBlinky" Width="40" Height="40" Background="Transparent">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content" Value="EDIT"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
Focusable="False"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Content" Value="Done"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Also, in order to change a property in a trigger it has to be set in a style, not directly. That is why your Content doesn't change in your MouseOver Trigger. If you remove the property setting for it and
add it into the Style with a Setter, it will allow the trigger to change it.
One downside to all this is it overrides all the default template triggers so you won't see when the ToggleButton is checked anymore unless you add a trigger for "IsChecked" too. (and if you need to alter the Background in the trigger, move the Background Property to a Setter like I did for Content)
Hope that helps...
Sorry to revive an old thread, but (for someone struggling) the following worked for me. This can be in App.xaml file under Application.Resources tag or directly in the Window.Resources. I originally needed it for a UWP application, then had to adapt for WPF for a different project:
<Style TargetType="ToggleButton" x:Key="TransparentToggleButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="RootGrid" Background="Transparent">
<ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then just style your ToggleButton:
<ToggleButton Style="{StaticResource TransparentToggleButtonStyle}">
(whatever content you want to present)
</ToggleButton>
Hope this helps someone,

Need help overriding a WPF button style background color.

I have the below code set for a custom button. But I want to change the background for a single button.
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle" Fill="#FF2F2FEA" Stroke="Black">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="3"/>
</Rectangle.Effect>
</Rectangle>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Bottom" Margin="2.833,0,2.5,1.162" RenderTransformOrigin="0.5,0.5" Width="69.667"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
The code below is meant to override the background color but doesn't. What am I missing? Thanks
<Style x:Key="SpecialButton" TargetType="Button" BasedOn="{StaticResource myButtonStyle}">
<Setter Property="Background" Value="PaleGreen" />
<Setter Property="Height" Value="19.96" />
</Style>
Add <Setter Property="Background" Value="#FF2F2FEA" /> to the myButtonStyle. And change the Fill on the Rectangle to Fill="{TemplateBinding Background}"
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#FF2F2FEA" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle" Fill="{TemplateBinding Background}" Stroke="Black">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="3"/>
</Rectangle.Effect>
</Rectangle>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Bottom"
Margin="2.833,0,2.5,1.162"
RenderTransformOrigin="0.5,0.5" Width="69.667"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After this, the two Buttons should show up properly.
<StackPanel>
<Button Content="BASE" Style="{StaticResource myButtonStyle}"></Button>
<Button Content="DERIVED" Style="{StaticResource SpecialButton}"></Button>
</StackPanel>
Result:
Explanation: if you change the Template of a Control you have to "wire-up" its properties (like Background, Foreground, HorizontalContentAlignment etc) to properties of elements in the ControlTemplate. After all you want to give the ability to end users of the control to modify the color, alignment etc, and not just have a Control with a static visual tree.

WPF ToggleButton XAML styling

So I have two toggle buttons that I am trying to combine - sort of. So the first button toggles the images based on whether it IsChecked is true or false, but this button has a border around it that I can't get rid of.
The second toggle button doesn't have a border and doesn't blink when clicked, but it also doesn't change images based on it's state.
What I want is the best of both worlds. Change the image AND get rid of the border. I have tried exactly 23 things and none of them work.
Here is the code I am using:
<ToggleButton x:Name="changeButBorderedBlinky" Margin="0,12,194,0" Width="82" Height="82" Background="Transparent" Padding="-1" Focusable="false" VerticalAlignment="Top" HorizontalAlignment="Right">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back2.png" Stretch="Fill" />
</Border>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back.png" Stretch="fill" />
</Border>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<ToggleButton x:Name="noChangeNoBorder" Margin="0,12,104,0" VerticalAlignment="Top" HorizontalAlignment="Right" Height="80" Width="80" >
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="border" >
<Image x:Name="img" Source="images/buttonimages/back2.png" />
</Border>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
Thanks for any help on this. It's driving me insane.
Your customization options are endless in either case. Have you ever tried Expression Blend? It comes along with Visual Studio 2013 Community (which is free to use) and it would let you customize either control any way you want.
Here, done using Expression Blend, no blink, no border, image swapping:
<ToggleButton x:Name="changeButBorderedBlinky" Margin="0,12,194,0" Width="82" Height="82" Background="Transparent" Padding="-1" Focusable="false" VerticalAlignment="Top" HorizontalAlignment="Right">
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="ToggleButton.IsChecked" Value="True"/>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back2.png" Stretch="Fill" />
</Border>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back.png" Stretch="fill" />
</Border>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Try to use slightly modified XAML pertinent to your first ToggleButton:
<ToggleButton x:Name="changeButBorderedBlinky"
Margin="0,12,194,0"
Width="82" Height="82"
Background="Transparent"
Padding="-1"
Focusable="false"
VerticalAlignment="Top" HorizontalAlignment="Right">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Content">
<Setter.Value>
<Image Source="images/buttonimages/back2.png" Stretch="Fill" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="images/buttonimages/back.png" Stretch="fill" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
You can also try to customize other properties, for eg:
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="BorderBrush" Value="Transparent">
For more styling options refer to: http://msdn.microsoft.com/en-us/library/cc296245%28v=vs.95%29.aspx
Hope this will help. Regards,

Disabling checkbox checking in WPF

I want to make impossible checking checkbox in WPF (from C# code). Only unchecking would be allowed.
How can I do it?
PS.Writing event handler on Click event which would immediately uncheck checkbox after checking it is not acceptable.
[edit]Checkbox should always be enabled, so that user can think that checkbox can be checked. It's strange but it's specific programme.
<CheckBox Content="Checkbox"
IsEnabled="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" />
Edit after being informed that the checkbox always has to look to be in an checkable state, even when it's not. Here is a working example:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" x:Class="WpfTest.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ControlTemplate x:Key="DeceptiveCheckbox" TargetType="{x:Type CheckBox}">
<BulletDecorator Background="Transparent" SnapsToDevicePixels="True">
<BulletDecorator.Bullet>
<Microsoft_Windows_Themes:BulletChrome BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" IsChecked="{TemplateBinding IsChecked}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"/>
</BulletDecorator.Bullet>
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="HasContent" Value="True">
<Setter Property="FocusVisualStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="14,0,0,0" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Padding" Value="4,0,0,0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid>
<CheckBox Content="CheckBox" IsEnabled="{Binding IsChecked, RelativeSource={RelativeSource Self}}" Template="{StaticResource DeceptiveCheckbox}" />
</Grid>
</Window>
The fix was simple. I simply created a copy of the current checkbox template and removed:
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
How about this:
<Grid>
<Grid.Resources>
<Style TargetType="CheckBox">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="IsEnabled" Value="False" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<CheckBox IsChecked="True" />
</Grid>
This approach has the benefit of being applied to all (as-is) or many (if you apply a x:Key attribute and then assign the resource to the desired checkboxes) without needing to do anything special or change the bindings of the individual checkboxes.
An easy solution could be to bind the IsEnabled property to be equal to the IsChecked property.

ListBoxItem ControlTemplate and ItemTemplateSelector

I'm trying to set a ControlTemplate to the ListBoxItem control, right now I haven't made any modification, it's as it comes out of the box:
<ControlTemplate TargetType="ListBoxItem"
x:Key="listBoxItemCustomTemplate">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
Name="Bd"
SnapsToDevicePixels="True">
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Selector.IsSelected">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelected">
<Condition.Value>
<s:Boolean>True</s:Boolean>
</Condition.Value>
</Condition>
<Condition Property="Selector.IsSelectionActive">
<Condition.Value>
<s:Boolean>False</s:Boolean>
</Condition.Value>
</Condition>
</MultiTrigger.Conditions>
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" />
</Setter.Value>
</Setter>
</MultiTrigger>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This works fine, the problem is when I try to use an ItemTemplateSelector in my ListBox. The DataTemplateSelector code doesn't even run, apparently there's something preventing the ItemTemplateSelector from working in that ControlTemplate, but I'm not sure how.
This is the ListBox:
<ListBox x:Name="listBox"
ItemsSource="{Binding AllItems}"
ItemTemplateSelector="{DynamicResource ExperimentExplorerTemplateSelector}"
ItemContainerStyle="{DynamicResource customListBoxItemStyle}" />
And the style that sets the ControlTempalte:
<Style TargetType="{x:Type ListBoxItem}" x:Key="customListBoxItemStyle">
<Setter Property="Template" Value="{StaticResource listBoxItemCustomTemplate}" />
</Style>
Any ideas why this is happening?
Thanks.
It looks like you used ShowMeTheTemplate and this does not always work correctly.
Here is the ListBoxItem template's ContentPresenter from ShowMeTheTemplate (Aero):
<ContentPresenter
Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
and the same section from Blend:
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
and there are other differences as well but this line specifically:
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
is what is the cause of your DataTemplateSelector being bypassed. I can't say that I understand why because ContentStringFormat is supposed to be ignored if TemplateSelector is set.
The moral is that we need a more reliable way to extract the same templates/styles that Blend extracts.

Resources