How can styles be merged in Silverlight? - silverlight

My goal is to extend the already set style of an object. So assuming I have the following two styles:
<Style TargetType="Ellipse" x:Key="OriginalStyle">
<Setter Property="Fill" Value="Blue"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="200"/>
</Style>
<Style TargetType="Ellipse" x:Key="NewStyle">
<Setter Property="Fill" Value="Red"/>
</Style>
What I'd like to do is assign OriginalStyle to an Ellipse, then later apply the second style only changing the properties it affects. So ideally I want to do something like this:
Style OriginalStyle;
Style NewStyle;
Ellipse ellipse = new Ellipse();
ellipse .Style = OriginalStyle;
// Later in an event hanler
ellipse.Style = NewStyle; // I would want to keep the settings from the old style in here: in this example setting the style like this would make me lose the Width and Height properties!
I've tried to dynamically construct a new Style and add the properties of NewStyle and OldStyle - however the Property property of the styles are always null so this lead to a dead end:
Style combinedStyle = new Style();
foreach (Setter setter in Old.Setters)
{
combinedStyle.Setters.Add(setter); // Get exception "Element is already the child of another element."
}
foreach (Setter setter in NewStyle.Setters)
{
combinedStyle.Setters.Add(setter); // Get exception "Element is already the child of another element."
}
It seems like there is no way to dynamically merge styles in Silverlight. Could someone confirm this or show me a better approach to achieve merging?

Does "BasedOn" work in Silverlight? // wpf developer, never sure

You can do it simply like this:-
<Style TargetType="Ellipse" x:Key="OriginalStyle">
<Setter Property="Fill" Value="Blue"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="200"/>
</Style>
<Style TargetType="Ellipse" x:Key="NewStyle" BasedOn="{StaticResource OriginalStyle}">
<Setter Property="Fill" Value="Red"/>
</Style>
Note that the order of appearance of such Style elements is important, you can not base a style on something that the XAML parser has not yet processed.

Related

XAML Style Trigger - Change Style ONLY for Object of with a specific Name

I am new XAML however I am given the task to override some styles for certain elements within an existing application.
In my custom Theme, I am attempting to override the style of a BORDER control.
From what I can tell (using Snoop) to inspect the application, the element I want to change is just a plain border.
The border also seems to have a Name of "SubMenuBorder". Please see the image below.
Here is the latest iteration of my style snippet in which I am trying to set the border control's Background, BorderBrush and BorderThickness BUT ONLY if the control has a name of "SubMenuBorder"
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<Trigger Property="Name" Value="SubMenuBorder">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="20"></Setter>
</Trigger>
</Style.Triggers>
</Style>
Unfortunately the above does NOT work.
The style trigger does not seem to fire/apply to the intended control.
If I simplify things further and just style ALL borders with the following snippet, then it seems to work and the border control I want to change, is styled, but so is every other border control in the application.
<Style TargetType="{x:Type Border}">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="20"></Setter>
</Style>
Further Findings
I attempted to use a DataTrigger... which unfortunately doesn't work either.
Snoop shows below that the data trigger is being satisfied, however on the second image below you can see that the property of the background and borderbrush are still from the parenttemplate.
Any ideas please?
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Name}" Value="SubMenuBorder">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="20"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
You cannot use triggers to modify a Border that is defined in a ControlTemplate, with the exception of using an implicit Style that applies to all elements of the type specified by the TargetType property of the implicit Style.
You will either have to modify the ControlTemplate itself, or programmatically find the Border element in the visual tree and then change its runtime property values. The first approach, i.e. modifying or creating a custom template, is the recommended approach.
The name "SubMenuBorder" is only known and applicable within that Border element's namescope.

MahApps.Metro change ToggleSwitch style

I'm testing wpf applications using MahApp.Metro.
Somehow I'm not able to change the style of the ToggleSwitch. I just want to change simple properties like foreground or background of the switch. What am I doing wrong?
Mainwindow.xaml
<Style x:Key="flyoutToggleSwitchStyle" TargetType="{x:Type Controls:ToggleSwitch}" BasedOn="{StaticResource {x:Type Controls:ToggleSwitch}}">
<Setter Property="BorderBrush" Value="WhiteSmoke"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="Yellow"/>
<Setter Property="OnLabel" Value="Yes"/> <!--<<<---THIS WORKS!!-->
<Setter Property="OffLabel" Value="No"/>
</Style>
<Controls:ToggleSwitch Style="{StaticResource flyoutToggleSwitchStyle}">
<Controls:ToggleSwitch.Header>
<TextBlock>
Test
</TextBlock>
</Controls:ToggleSwitch.Header>
</Controls:ToggleSwitch>
Now there is a new ToggleSwitch property called SwitchForeground which allows changing the colour for ON position (tested on v0.14).
Example:
<controls:ToggleSwitch SwitchForeground="{StaticResource MyGreen}" />
The problem is that in the Mahapps.Metro ToggleSwitch most of the properties can not be changed within a style, because there is no TemplateBinding or Key defined in the original template definition.
So the style can only be changed by creating a new template. For this the ToggleSwitch and the ToggleSwitchButton templates have to be changed.
Issue on GitHub
Source of the templates

Style a custom property of a custom control

In an application that I am working I need to have all of my next buttons look the same. So my plan was to make a style called next button style and apply as needed. However I need to set some dependency properties on the button to be the same.
Here is the xmal for the style
<Style x:Key="NextButtonStyle" TargetType="diControls:DIButton">
<Setter Property="Margin" Value="5"></Setter>
<Setter Property="DIButtonStyle" Value="DIGreenImageButtonWithText_Medium"></Setter>
<Setter Property="Image" Value="RightArrowIcon_Gray"></Setter>
<Setter Property="HoverImage" Value="RightArrowIcon_White"></Setter>
<Setter Property="Command" Value="{Binding Path=NextPressedCommand}"></Setter>
</Style>
The custom properties DIButtonStyle,Image and HoverImage all say an exception has been thrown by the target of an invocation. Is there any way around this error?
Thanks!

How to add new setter programatically in existing ItemContainerStyle in WPF?

I have item container style for list view like below :
<ListView.ItemContainerStyle>
<Style>
<Setter Property="Padding" Value="0"></Setter>
<Setter Property="Margin" Value="0,0,0,-1"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=EventType}" Value="2">
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="White"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
Now I need to add new setter for context menu programatically based on item data. How can I do it ?
Please guide me.....
Thanks
I have to display Images dynamically and show/hide depends on state of checkboxes using Style and DataTrigger.
<Image Source="/WpfApplication;component/Imgs/img1_1.png">
<Image.Style>
<Style>
<Setter Property="Image.Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=isDisplayingImgSet1, Path=IsChecked}" Value="True">
<Setter Property="Image.Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
After spec modification i have to create checkboxes dynamically, then to set Style.
At beginning, I have the same error message.
Image img = new Image();
//..
img.Style.Setters.Add(setter);
img.Style.Triggers.Add(trigger);
//..After a 'SetterBaseCollection' is in use (sealed), it cannot be modified.
The solution is to create a style object and Affect it to Image.Style
//Visibility
DataTrigger trigger = new DataTrigger();
trigger.Binding = new Binding
{
ElementName = "isDisplayingImgSet"+NumSet,
Path = new PropertyPath(CheckBox.IsCheckedProperty)
};
trigger.Value = "True";
trigger.Setters.Add(new Setter(ContentControl.VisibilityProperty, Visibility.Visible));
Setter setter = new Setter(ContentControl.VisibilityProperty, Visibility.Collapsed);
Style style = new Style(typeof(Image));
style.Setters.Add(setter);
style.Triggers.Add(trigger);
img.Style = style;
Hope that helping you
PS : It's my first post
I have implemented logic to add setter dynamically in existing style like below :
listview1.ItemContainerStyle.Setters.Add(new Setter(Control.ContextMenuProperty,GetItemContextMenu(txtName.Text)));
But it gives me following error :
"After a 'SetterBaseCollection' is in use (sealed), it cannot be modified."
I think it is not possible to add new setter in sealed style. So I have got another temporary solution like assign context menu to whole listview rather than it's item on preview mouse right click event. So context menu will be same for all items then managed in coding based on data of selected item.
<ListView.ItemContainerStyle>
<Style>
<Setter Property="Padding" Value="0"></Setter>
<Setter Property="Margin" Value="0,0,0,-1"></Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=EventType}" Value="2">
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
If you create a new Style() and "re-add" the the setters, you can get around this issue if you are using Telerik.
private static void AddColumnSetter(GridViewColumn gridColumn, SetterBase setter)
{
var setters = new SetterBaseCollection();
if (gridColumn.CellStyle != null)
{
foreach (SetterBase setterBase in gridColumn.CellStyle.Setters)
{
setters.Add(setterBase);
}
}
setters.Add(setter);
gridColumn.CellStyle = new Style();
foreach (var setr in setters)
{
gridColumn.CellStyle.Setters.Add(setr);
}
}

Unable to set Background property of MenuItem for IsPressed event

I want to change the background of a MenuItem when the MenuItem is pressed.
<Style x:Key="{x:Type MenuItem}" TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="MenuItem.IsPressed" Value="True">
<Setter Property="MenuItem.Background" Value="#FFE389" />
<Setter Property="MenuItem.BorderBrush" Value="#C2762B" />
</Trigger>
</Style.Triggers>
</Style>
I tried doing the above, but the trigger does not seem to work. Is the Trigger wrong?
Update: It works for the event IsMouseOver but IsPressed does not seem to work
Update 2: It works for TopLevelMenuItems but does not work for TopLevelMenuHeaderItems.
Try this...which does not preface the property names with MenuItem and modify your TargetType and x:Key syntax...
<Style x:Key="MyStyle" TargetType="{x:Type MenuItem}">
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#FFE389" />
<Setter Property="BorderBrush" Value="#C2762B" />
</Trigger>
</Style.Triggers>
</Style>
EDIT:
Based on your updates take a look at how a default MenuItem is constructed via XAML. This should get you where you need to go in providing styling for the varying parts of the MenuItem. Note the use of the Role property within the MenuItem style dealing with the headers and items at both the top level and sub level.

Resources