WPF Style can't work on multiple controls - c#

I am using wpf style on my controls so that i can use an style on multiple controls at once. It usually works. for example i made an saveButtonStyle and i apply it on every save button on my application. But it doesn't work on MenuItems.
I made a style for my menuitems which contains an icon next to the items.
This is one screen shot of it.
You see the Datagrid has an ContextMenu and within it there is multiple menu items. in this case pay attention to Set Alarm. it has an icon. This Set Alarm Menu item is also in another menu datagrid next to this one. When i click that one
it appears too
But problem is when i right click back to the other datagrid the icon is gone and wont come back. this is the screen shot
Here is the style I made
<Style x:Key="menuItemAlert" TargetType="{x:Type MenuItem}">
<Setter Property="Icon">
<Setter.Value>
<Image Source="Content/AlertIcon.png" Width="20" Height="20" />
</Setter.Value>
</Setter>
</Style>
And here is how I apply it to my controls
<MenuItem x:Name="customerContextMenuSetAlarm" Header="SetAlarm" Style="{StaticResource menuItemAlert}" Click="customerContextMenuSetAlarm_Click"/>
Do you know why it happens?

style menuItemAlert creates only one instance of Image and can display it in one place only. to overcome this make a separate non-shared resource for that Image.
<Image x:Key="AlertIcon" x:Shared="False" Source="Content/AlertIcon.png" Width="20" Height="20" />
<Style x:Key="menuItemAlert" TargetType="{x:Type MenuItem}">
<Setter Property="Icon" Value="{StaticResource AlertIcon}"/>
</Style>

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>

How do I bind template with style?

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

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>

Silverlight Toggle Button Grouping

I'm developing a Silverlight app and would like to create a grouping of 5 toggle buttons (used for menu options) that animate when clicked (grow in size) and also cause any previously clicked buttons in the group to unclick and animate back to their shrunken size.
I know I could use a brute force approach where the app is directly aware of each button, but if I add or change the menu (add/remove a button) I'd have to remember to modify the code (which is bad since I'm forgetful). Is there a way to more intelligently group the buttons so that when one is clicked is can tell all the others in the group to unclick?
Thanks!
Todd
Special shout-out to Michael S. Scherotter for pointing me in the right direction to use RadioButton and a control template!
Here's the basic control template that I came up with. Put this in the App.xaml between the tags if you care to see it. The UX folks will give it a once over to pretty it up, but for now, it works as a radio button that looks like a toggle button (or just a button), but has a groupname.
An important note: this template doesn't have any of the basic button animation, so it won't press down when clicked... That's the UX work I mentioned above.
<Style x:Key="MenuButton" TargetType="RadioButton">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="25"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Border BorderBrush="DarkGray" BorderThickness="3" CornerRadius="3" Background="Gray">
<!-- The ContentPresenter tags are used to insert on the button face for reuse -->
<ContentPresenter></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I was trying to do the same thing and I found this old post. Let me update it a bit...
Todd seems to be like many other lazy programmers, letting the UX guys do all the work. :) So here is Todd's solution with actual toggle buttons as radio buttons in a group:
<RadioButton GroupName="myGroup"
Style="{StaticResource MenuButton}"
Content="One"
IsChecked="True" />
<RadioButton GroupName="myGroup"
Style="{StaticResource MenuButton}"
Content="Two" />
<RadioButton GroupName="myGroup"
Style="{StaticResource MenuButton}"
Content="Three" />
<Style x:Key="MenuButton" TargetType="RadioButton">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="25"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Border BorderBrush="DarkGray" BorderThickness="3" CornerRadius="3" Background="Gray">
<ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<ToggleButton.Content>
<ContentPresenter></ContentPresenter>
</ToggleButton.Content>
</ToggleButton>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And now you'll have your pretty button rollover effects and all that and only one toggle button will be able to be 'checked' at one time.
Both radio buttons and toggle buttons can be three state, and you can bind the 'IsThreeState' property of the toggle button as well in the same manner that I bind 'IsChecked' here. But by default they are two state.
Also, the long form binding is important here as the shortcut {TemplateBinding IsChecked} would default to one way and we need them to stay in sync both ways.
This example does not, of course, animate the buttons with size changing and all that Todd originally posted, but it does give you regular buttons that you can easily distinguish as being checked or not.
Give all of the RadioButton objects the same GroupName.

Categories