I have a very strange problem trying to change the controltemplate for a button in WPF (c#).
I now have the following code:
<Window.Resources>
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MacOSX-Close" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Black" BorderThickness="0">
<Image x:Name="bgimg" Source="bin/debug/Ressources/Images/GUI/frame-btn-defaulted.png"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="bgimg" Property="Source" Value="bin/debug/Ressources/Images/GUI/frame-btn-defaulted.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
So this isn't working. It says
"{DependencyProperty.UnsetValue}" is no valid value for property "System.Windows.Controls.Image.Source" on a setter.
And when I tried using multiple images in a grid (because you can only set one child) and modified the "visibility" property, the button didn't show up at all!!! No button, no image. And, yes, I am sure the image exists.
But the source is relative to the solution root, not to the compiled program... does this matter? Please help me :) I'm gettin' little desperate here... :(
Best regards ;)
And please ask if somethin's not clear to you.
Create folder like say Resources in your project and put image in your resources folder and their build action should be set to Resource. Then you can set Source = "/Resources/frame-btn-defaulted.png"
Related
This question already has answers here:
Overriding application wide style
(2 answers)
Closed 3 years ago.
I'm in pretty new to C# WPF and recently meet a very weird problem.
I'm managing style sheet xaml files as following pictures and code.
File Structure
[ App.xaml ]
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/StyleText.xaml"/>
<ResourceDictionary Source="Styles/StyleButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
[ StyleText.xaml ]
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
[ StyleButton.xaml]
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock x:Name="TblockTest" Background="Gray" Foreground="Blue">
<TextBlock.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Green"/>
</Style>
</TextBlock.Resources>
<ContentPresenter x:Name="CpCustomButton" ContentSource="Content"/>
</TextBlock>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Setter TargetName="CpCustomButton" Property="TextBlock.Foreground" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
These are test codes to reproduce the problem.
What I want to do is ignore the style of StyleText.xaml inside StyleButton.xaml without addressing key to the textblock style in StyleText.xaml
As you know, textblock style without key will serve the global style, and so I don't have to insert annoying 'style={~~}' code per textblock.
But now, I can't avoid that it infects the style of textblock inside of control template for other control like button.
As you can see in the StyleButton.xaml, I tried several things that I can think and googled so much times, but nothing solves this problem clearly.
The content of a button always shows in Red which is the color addressed by StyleText.xaml.
What should I do to solve the problem?
I also attach my test solution noted above.
https://www.dropbox.com/s/no0j60px2qnl51y/WeirdProblem.zip
Thanks to read.
I downloaded the solution and here's a fix: move the TextBlock Foreground style from the TextBlock.Resources to ContentPresenter.Resources like this
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock
x:Name="TblockTest"
Background="Gray"
Foreground="Blue">
<ContentPresenter x:Name="CpCustomButton" ContentSource="Content">
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Green" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</TextBlock>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Setter TargetName="CpCustomButton" Property="TextBlock.Foreground" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm not sure why it didn't use the style from the TextBlock.Resources when that is a parent to the ContentPresenter.
Hope that helps. Michal
I would like to make a game like Shakes & Fidgets. I got stuck at the Main menu, where I already overcomplicated stuff as I always do. I made a grid layout, where I will put the buttons, but every button is a picture. I use ImageBrush for every button's picture I want to create.
I would like to create ONE style for every button so they change their backgrounds based on the x:Name or x:Key they have. So a Button with x:Name or x:Key "PlayGame" would find it's as the PlayGame.png, PlayGame_Hover, PlayGame_OnClick where "PlayGame" is a variable.
In other words I would like to have a style that can filter the x:name, or x:key of a button, and uses it as a variable later on so I can do this: {StaticResource VARIABLENAME}
The Code I have now is:
<ImageBrush x:Key="PlayGame">
<ImageBrush.ImageSource>
<BitmapImage UriSource="./Pictures/PlayGameButton.png"/>
</ImageBrush.ImageSource>
</ImageBrush>
<ImageBrush x:Key="PlayGame_Hover">
<ImageBrush.ImageSource>
<BitmapImage UriSource="./Pictures/PlayGameButton_Hover.png"/>
</ImageBrush.ImageSource>
</ImageBrush>
<ImageBrush x:Key="PlayGame_OnClick">
<ImageBrush.ImageSource>
<BitmapImage UriSource="./Pictures/PlayGameButton_OnClick.png"/>
</ImageBrush.ImageSource>
</ImageBrush>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource PlayGame}" />
<Setter Property="FontSize" Value="15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource PlayGame_Hover}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{StaticResource PlayGame_OnClick}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I found a not very effective solution, but not the one I actually want
You can give the Style an
x:Key="styleKey"
and you have to give the button this part:
Style="{StaticResource styleKey}"
This way you will have to make a style for every different button you want to have, but it will work, and you will be happy about it if efficency is not key.:D
Hi I just wondered if I could get some help, I'm having alot of trouble getting the data trigger to work, if i remove the data trigger and place the drop shadow just as a setter it works. But i want to be able to give the user the option of turning on and off the drop shadow so I thought the data trigger would be the answer.
Basically I want to add the data trigger all over my control styles and just be able to change the fancyGraphics BOOL to TRUE or FALSE and have every controls drop shadow adjust.
Thanks in advance.
Here is my XAML
<sys:Boolean x:Key="fancyGraphics" >True</sys:Boolean>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#EEE"></Setter>
<Setter Property="Foreground" Value="#555"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="1" BorderBrush="#DDD">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#333"></Setter>
<Setter Property="BorderBrush" Value="#888"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=fancyGraphics}" Value="True">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="20"
Opacity="0.5"
ShadowDepth="0"
Color="#111" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
The binding in DataTrigger looks for a property named fancyGraphics. But, fancyGraphics is a static resource. You should define the binding as such:
<DataTrigger Binding="{Binding Source={StaticResource fancyGraphics}}" Value="True">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="20"
Opacity="0.5"
ShadowDepth="0"
Color="#111" />
</Setter.Value>
</Setter>
</DataTrigger>
I try to change the background of a toggle button everytime when it is checked or not,using 2 pictures. At runtime, the toggle button is simple and I don't see any image. This is my code:
<Canvas Height="25" Name="canvas1" Width="186" Background="White">
<ToggleButton Name="toggle1" Height="25" Padding="0" Width="27" Canvas.Left="131" Canvas.Top="0" BorderBrush="{x:Null}" Foreground="{x:Null}">
<ToggleButton.Resources>
<Style x:Key="OnOffToggleImageStyle" TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/WpfApp;component/Images/image1.png" Stretch="Uniform" TileMode="None" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/WpfApp;component/Images/image2.png" Stretch="Uniform" TileMode="None" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Multiple things we can point here.
Firstly you're specifying the Style in ToggleButton.Resources with a x:Key. Thus it's not implicitly set. Setting a Style in resources of the item for which it applies in it's own scope is kinda weird. Rather just apply the Style directly as <ToggleButton.Style>.
Next, when working with Style.Triggers, make it a practice to specify a default Setter. This will prevent some headache for you. Also now instead of having two triggers for IsChecked=False/True, you only need one trigger as the other Background can be set as default.
Finally it seems like all you need from the ToggleButton is the IsChecked property and switch an Image. So just override the Template and provide a simple one yourself. This way you assure the behavior to stay consistent in all version of the OS and not rely on internal default template's working nicely for your customization(which wouldn't work in Windows-8 btw, what you're trying here for IsChecked=True due to internal overrides in default ControlTemplate)
So putting this all together we get:
<Style x:Key="MyToggleButtonStyle"
TargetType="ToggleButton">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/WpfApp;component/Images/image2.png"
Stretch="Uniform"
TileMode="None" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/WpfApp;component/Images/image1.png"
Stretch="Uniform"
TileMode="None" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
and apply it to your ToggleButton
<ToggleButton Name="toggle1" Height="25" Padding="0" Width="27" Canvas.Left="131" Canvas.Top="0" BorderBrush="{x:Null}" Foreground="{x:Null}" Style="{DynamicResource MyToggleButtonStyle}">
you can ofc remove the Key in the Style and make it implicitly apply to "all" ToggleButton's within the scope of the Style definition if you choose to.
Can you check if the build action for your images is Embedded Resource please?
Define the style directly for your togglebutton like below. it should fix your issue:
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/WpfApp;component/Images/image2.png" Stretch="Uniform" TileMode="None" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/WpfApp;component/Images/image1.png" Stretch="Uniform" TileMode="None" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
You should remove the x:Key and it will work.
I've got a UserControl which is a modified toggleButton.
I've added two String properties to it so I can change (or bind) them in blend, which I want to be the text displayed when the button is toggled. ie when checked, one string is displayed, when unchecked - the other.
Setting the text is fine, and toggling the UserControl is fine, but I don't know how to set the content of the contentpresenter from a property of the toggle by a trigger. Here's a rough look at the code:
<UserControl
x:Name="UserControl"
<UserControl.Resources>
<Style x:Key="BiTextToggleButtonWithBorder" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<Path x:Name="path"
Data="M28,0.5 L28.071953,0.50129622 28.092436,0.5 115.90756,0.5 C117.89162,0.50000113 119.5,2.5147196 119.5,5.0000013 L119.61492,36.460156 119.61432,36.857203 C117.1338,37.367692 108.82679,39.239366 106.37993,47.492391 L44.667,47.5 28.092436,47.5 4.9999995,47.5 C2.5147185,47.5 0.5,45.485283 0.5,43 L0.5,21 0.51801485,20.64324 0.5,20.0835 C0.5,9.2678322 12.812169,0.50000072 28,0.5 z"
Stretch="Fill"
<ContentPresenter
x:Name="contentPresenter"
Content="{Binding}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" TargetName="contentPresenter" Value="{Binding whatgoeshere!?}"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content" TargetName="contentPresenter" Value="whatgoeshere!?"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<ToggleButton
x:Name="ToggleButton"
Style="{DynamicResource BiTextToggleButtonWithBorder}"
FontSize="18.667"
Foreground="{DynamicResource WhiteText}"/>
</Grid>
</UserControl>
I can't even find the property I want to change. I've done similar bindings to objects within a UserControl before, but nothing that is in a style and in a controlpresenter.
What am I missing?
have you tried changing the {Binding} to a {TemplateBinding} ? (MSDN documentation here)