How do I bind template with style? - c#

I have a C# WPF application where I need to create a bunch of image/text buttons with different colors. To that end I created an ImageButton derived from Button class.
I want my button to have round corners so I have created the following control template:
<ControlTemplate x:Key="RoundedButtonTemplate" TargetType="{x:Type MyProject:ImageButton}">
<Grid>
<Border x:Name="border" Background="WHAT DO I PUT HERE?" CornerRadius="10"/>
</Grid>
</ControlTemplate>
Now I want to be easily able to change the color of the border above, just by changing styles in XAML. I have the following styles defined.
Green Button Style:
<Style x:Key="GreenButtonStyle" TargetType="{x:Type MyProject:ImageButton}">
<Setter Property="Background" Value="{DynamicResource GreenButtonBrush}"/>
RoundedButtonTemplate}"/>
</Style>
Blue Button Style:
<Style x:Key="GreenButtonStyle" TargetType="{x:Type MyProject:ImageButton}">
<Setter Property="Background" Value="{DynamicResource BlueButtonBrush}"/>
RoundedButtonTemplate}"/>
</Style>
My client code looks like this:
<local:ImageButton HorizontalAlignment="Left" Margin="24,19.234,0,20" Width="97" Grid.Row="3" Style="{DynamicResource GreenButtonStyle}" Template="{DynamicResource RoundedButtonTemplate}"/>
My question is how do I make the template know which style to use? I tried adding the following property to my style, but didn't have much success:
<Setter Property="Template" Value="{DynamicResource RoundedButtonTemplate}"/>

I'm guessing that ImageButton inherits from UserControl since this is a composite control. If not, you probably should. MSDN discusses inheriting from Control vs UserControl. I would put the Border in there, and inside a Button and a TextBlock or something.
One way to do this would be to define a Dependency Property on your new ImageButton class, something like "BorderBackground." You link this up to change the Border's Background color when you set it. I can provide sample code if you like.
When you set your styles, the target property would be "BorderBackground." This would eliminate the needs for any change to the ControlTemplate, which I generally try to avoid.
Does this help at all?
Or answer your original question, I am not sure if the Template would know how to have the style applied since your style targets the Background of the ImageButton control, not the Background of the Border control.

I think I figured it out. All that was needed was placing the following text in my template definition:
Background="{TemplateBinding Background}"
More information can be found in this article:
TemplateBinding: a bridge between styles and templates

Related

WPF using style that contains another style

I'm trying to make a progress bar style that is re-usable.
So the idea here is very simple. I have a style already with target type ProgressBar, and it's just a spinny circle that fills as it goes from 0-100%. However, in order to make it re-usable and modular, I do not want to hard-code the text that goes along with it - it should be optional.
So I want to create another style that DOES include text "Downloading... X/Y MB". For this I take Value for X, Maximum for Y, and Tag for the unit. I want to include the same spinny circle thingy for the graphical part on the left. How can I do this? With BasedOn property, I think you can only set something already there to be different. What if I want to add additional elements (like textblocks in this case)?
If only text value differentiates then within style you can bind propertie's value to parent's property like Tag where at every single either style or element you adjust it to specific requirement.
<Window.Resources>
<Style x:Key="FirstButtonStyle" TargetType="Button">
<Setter Property="Content" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SecondButtonStyle" TargetType="Button" BasedOn="{StaticResource FirstButtonStyle}">
<Setter Property="Content" Value="2"/>
</Style>
</Window.Resources>
<StackPanel>
<Button Style="{StaticResource FirstButtonStyle}"/>
<Button Style="{StaticResource SecondButtonStyle}"/>
</StackPanel>
The outcome is 1 and 2. If your intent is to inject some UI element within style then there is no such an option, alas. Style needs to be rewritten once again.

Cannot override controls foreground colour in wpf

Hi all this is a problem that has been driving me crazy for a few days now.
Put simply whenever i declare a foreground colour on anything that derives from a TextBlock control that foreground colour is recognised at design time but at run time it always defaults to being black.
Its as if the foreground property is being ignored on the control.
So for example normally i would expect the following to render a button with white text:
<Button x:Name="MyButton" Content="Hello World" Foreground="White" ... />
However this renders a button and the foreground text colour is black. Its effectively ignoring the Foreground setter property.
The only way to get this to work as expected is to the do following:
<Button x:Name="MyButton" .... >
<TextBlock Text="Hello World" Foreground="White"/>
</Button>
This way works and the button renders correctly with white text. But i know i shouldnt have to explicitly define the buttons textblock like this.
The same behaviour occurs with anything that derives from textblock.
Does anyone have any idea why this is happening ?
UPDATE:
I have checked my solution for styles that are applied to TextBox. I have defined my own style on the TextBlock which is:
<Style x:Key="TextBlockText" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#FF63798F"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
Which as you can see defines a value for the foreground. However when i remove this style from my resource dictionary the above problem still remains.
Additional information is that I am using the MahApps.Metro libraries and Im wondering if this is causing the issue.
Does anyone have any other ideas ? Or even thoughts of where to investigate ??
Every control in WPF has a Template associated with it. I think somehow a style defined on your button which does not count the foreground property.
For instance,
<Style x:Key="DialogButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"
Stroke="{TemplateBinding BorderBrush}"/>
<TextBlock Foreground="{TemplateBinding Foreground}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/></TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Can you use Style={StaticResource DialogButtonStyle} and define foreground for the Button. See here we used TemplateBinding on Foreground of the TextBlock rather than defining the color inside it.
I'd recommend keeping your TextBlock style as it is, and in your Button or other controls, at the Template level, add a new Resource with a TextBlock style. It will be in that template's domain so it won't affect the other textblocks but will override the style of the main TextBlock.
For example:
<ControlTemplate>
<Grid>
<Grid.Resources>
<!-- Put a new/duplicate TextBlock Style here with
the appropriate Foreground color, or TemplateBinding
and it will override it for this Grid's children -->
</Grid.Resources>
<TextBlock />
</Grid>
</ControlTemplate>

Is it possible to put Button in WPF slider thumb?

Is it possible to put Button in WPF slider thumb? Not custom thumb itself but simply add button on it?
I'm not sure how you would put a button in it without customizing the Thumb. If you're interested in customization:
It looks like this sample customizes the Thumb as well as the rest of the slider.
<Style x:Key="CustomThumbForSlider" TargetType="{x:Type Thumb}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Ellipse Fill="#FF8F4040" Stroke="#FF000000" Height="15" Width="15"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Having never personally done this, my guess would be that you just replace the following portion with the control template you're using:
<Ellipse Fill="#FF8F4040" Stroke="#FF000000" Height="15" Width="15"/>
EDIT: Unless you explicitly need the functionality of a button, you should probably use something like a TextBlock to display your value.
I'm not sure I understand the question, but : the whole interest of WPF is the ability to customize each element with ControlTemplates. Here is an article from Josh Smith explaining it : Understanding Templates in WPF and here a tutorial on customizing sliders : Custom sliders.
Edit: forgot to put the link title. My bad.

WPF: TextTrimming on a ContentPresenter

Is there a simple way to just get TextTrimming to work with a ContentPresenter?
I have implict styles for TextBlock and AccessText that have TextTrimming set to CharacterEllipsis, but it's not picked up by the ContentPresenter. I can change the ContentPresenter to an AccessText or TextBlock and set it there, but then the template only handles text content.
Any suggestions?
Thanks!
Implicit Styles for elements that derive from UIElement, but not Control, are not applied if the element is defined in a control's Template unless the implict Style is defined in the application Resources. The same holds true for TextBlocks used by ContentPresenter.
For example, in the following XAML the TextBlock that is ultimately used to present the button's content will not get the implicit Style:
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
</Style>
</Window.Resources>
<StackPanel>
<Button Content="Will not be red" />
<TextBlock Text="Will be red" />
</StackPanel>
If you take that exact same Style and move it to the application's Resources, then both will be red:
<Application.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>
So you can either move your implicit Style to application resources, which is generally not a good idea. Or you can customize the display for the specific scenario you have. This can include adding an implicit DataTemplate, or customizing a control's Template.
If you can provide more information, then it would be easier to know which is the best approach.
Thanks to this Gist by James Nugent: "WPF style which puts character ellipsis on button contents without replacing the ContentPresenter with a TextBlock and thus losing the ability to support access keys."
This worked for me:
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="TextTrimming" Value="CharacterEllipsis"></Setter>
</Style>
</ContentPresenter.Resources>

Setting a style on Control type not working

I'm writing a very basic WPF dialog and want to apply a simple style to all objects that inherit from the Control class. The code I'm using:
<Window.Resources>
<Style TargetType="{x:Type Control}">
<Setter Property="Margin" Value="20"/>
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Text="some text"/>
<TextBox x:Name="x_NameTextBox"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="x_CancelButton" Click="x_CancelButton_Click" Content="Cancel"/>
<Button x:Name="x_OkButton" Click="x_OkButton_Click" Content="OK"/>
</StackPanel>
</StackPanel>
</Window>
The Style defined above doesn't change the layout of the window at all unless I specify a key and set the style on each individual object, which is exactly what I'm trying to avoid. It also works for more specific types (setting the TargetType to Button, for example.)
Any ideas why this isn't working?
Every control when it gets instantiated it gets its Style from the explicitly defined resource or look for the immediate parent where it can get a default style. In your case the Button control will get its default Style from the platform because your App haven't defined one. Now that platform Button Style has no way to know about your custom defined Control base style. Because styles will look for a base style only when you explicitly define BasedOn
So you got only two ways
1. Define Style for every control - which you don't want I think.
2. Define Styles for the controls you are interested and set the BasedOn
<Style TargetType="{x:Type Control}">
<Setter Property="Margin" Value="20"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Control}}">
</Style>

Categories