Is there anyway to turn off a style programatically?
As an example, I have a style that is linked to all textboxes
<Style TargetType="{x:Type TextBox}">
I would like to add some code to actually stop the style elements being used, so basically reverting back to the default control style.
I need a way to make a switch in my styles, so I can switch between Windows default style and my custom style through C# code.
Is there anyway to do this?
Thanks
Working Solution
Switching between themes in WPF
For setting the style to default,
In XAMl use,
<TextBox Style="{x:Null}" />
In C# use,
myTextBox.Style = null;
If style needs to be set as null for multiple resources, see CodeNaked's response.
I feel, all the additional info should be in your question and not in the comments. Anyways, In code Behind I think this is what you are trying to achieve:
Style myStyle = (Style)Application.Current.Resources["myStyleName"];
public void SetDefaultStyle()
{
if(Application.Current.Resources.Contains(typeof(TextBox)))
Application.Current.Resources.Remove(typeof(TextBox));
Application.Current.Resources.Add(typeof(TextBox),
new Style() { TargetType = typeof(TextBox) });
}
public void SetCustomStyle()
{
if (Application.Current.Resources.Contains(typeof(TextBox)))
Application.Current.Resources.Remove(typeof(TextBox));
Application.Current.Resources.Add(typeof(TextBox),
myStyle);
}
You could inject a blank Style that would take precedence over your other Style. Like so:
<Window>
<Window.Resources>
<Style TargetType="TextBox">
<Setter Property="Background" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="TextBox" />
</Grid.Resources>
</Grid>
</Window>
In the example above, only the Grid's implicit Style would be applied to TextBoxes in the Grid. You could even add this to the Grid programmatically, something like:
this.grid.Resources.Add(typeof(TextBox), new Style() { TargetType = typeof(TextBox) });
I know the answer has been accepted, but i want to add my solution which works awesome in the following scenario:
One main application using mahapps.metro
additional project imported from the main application with no reference to mahapps.metro, it is imported as a plugin (loading compiled .dll on the fly)
using the < ToolBar> re-styles everything to null therefore the mahapps.metro styles are not being applied to items inside the toolbar.
usercontrol is used to provide custom controls to the main application.
in the user control root set the resources:
<UserControl.Resources>
<Style x:Key="ButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" />
<Style x:Key="ComboBoxStyle" TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}" />
</UserControl.Resources>
then the toolbar code can be the following
<ToolBar>
Block Template:
<ComboBox Style="{StaticResource ComboBoxStyle}"/>
<Button Content="Generate!" Style="{StaticResource ButtonStyle}"/>
</ToolBar>
this successfully applies the main application style to the controls inside the < ToolBar>
In Xaml, you can override this by setting a style explicitly. In code-behind, you can also set the style explicitly.
<TextBox Style="{StaticResource SomeOtherStyle}"/>
myTextBox.Style = Application.Resources["SomeOtherStyle"];
Related
I'm using MaterialDesignInXaml for WPF which provides 3rd party controls and styles. I need to edit one of these styles by changing one property.
I am using an Expander control which has a template creating a bunch of child controls. I've discovered the child 'Border' control (4 layers deep) has the property (padding) which I need to set to zero.
See this output from Snoop showing the property I need to change:
Link to image
My question is how can I do this? I've tried extending the style used by the control as follows, but it isn't changing anything so I assume I'm doing something wrong?
<Style TargetType="{x:Type Expander}"
x:Key="MaterialDesignExpanderHeadless"
BasedOn="{StaticResource MaterialDesignExpander}">
<Style.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Padding" Value="0"></Setter>
</Style>
</Style.Resources>
</Style>
I am able to use the style like this. And I know this is working for sure:
<Expander Header="Header Content" Style="{StaticResource MaterialDesignExpanderHeadless}">
Some Content
</Expander>
You're right, this method should work. Something else is setting the border's padding.
Snoop is telling you the padding is defined by the parent template, which could be the HeaderSite (ToggleButton).
You could try to extend the ToggleButton style (BasedOn) or redefine it locally.
I have created custom window classes for dialogs like this:
public class DialogBase : Window
{
// common stuff here
}
public class DialogOkCancel : DialogBase
{
static DialogOkCancel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogOkCancel),
new FrameworkPropertyMetadata(typeof(DialogOkCancel)));
}
// specific stuff here
}
The styles looks like this, and contains dialog specific things such as title bar, OK/Cancel buttons etc.
<Style x:Key="DialogBaseStyle" TargetType="{x:Type base:DialogBase}" BasedOn="{StaticResource {x:Type Window}}">
<Setter Property="ShowInTaskbar" Value="False"/>
<!-- more stuff here -->
</Style>
<Style TargetType="{x:Type base:DialogOkCancel}" BasedOn="{StaticResource DialogBaseStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type base:DialogOkCancel}">
<!-- more stuff here -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This works perfectly fine during runtime. Also, the dialogs displays fine in XAML Designer.
However, in XAML Designer, the DialogOkCancel style gets applied to other all other windows as well, such as the application main window (which simply derives from plain Window). The title bar, buttons and everything. I don't really get this, as the TargetType is specific. This does not occur at runtime.
What am I not seeing here ?
Correct way to apply a style both while in designer mode and during runtime is to have declared the style in App.xaml. Best practice would be to have a MergedDictionaries, containing a reference of your various style dictionaries, which will be in other files.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Converters -->
<ResourceDictionary Source="Resources/Converters.xaml"/>
<!-- Windows -->
<ResourceDictionary Source="Resources/WindowStyles.xaml"/>
// ... and all others //
WindowStyles.xaml can contain the exact styles you wrote above. They will be applied to all DialogOkCancel windows, both in designer and runtime.
Hope that helped.
Edit (as commented: XY-Problem) - Problem:
I want to create my own control which has predefined styles and positions for special elements (Button,...), but in general everything should be able to be placed inside my custom control. The custom control in my case is just a "menubar" which should be able to be used anywhere in the "GUI code" - but there is no need it has to be there. But when it is used it should be the same style and behavior everywhere. A style is - I think - not enough, because there are also predefined elements in this menubar (e.g. Help is already in menubar)
Edit end.
I want to build a custom control (just a special stackpanel) in WPF with the following requirements:
can be used as any other control within a xaml
has defined styles for controls within the custom control
First I simply tried to create a UserControl containing a stackpanel with defined styles (in the xaml) for containing elements (e.g. Button). This UserControl contained the
<ContentPresenter />
in the xaml. With this method it is not possible to name the containing elements. E.g.:
<mynamespace:MyStackPanel>
<Button Name="w00t">This does not work!</Button>
</mynamespace:MyStackPanel>
Next try was to create a "real" custom control. This custom control is just a class without the xaml. Code is very simple. Class inherits from UserControl and just contains:
StackPanel sp = new StackPanel();
sp.Children.Add(new ContentPresenter());
this.AddChild(sp);
Woooohoooo, now it's possible to name the containing elements. But still a big problem: How to define the styles?
I could define the style for my very own custom control in a ResourceDictionary. But i have to add the ResourceDictionary to the global (App.xaml) Resources. And then I can define styles only for my custom control - not for the containing elements? - But anyway... doing it like this just feels wrong!
So the main question is: WHAT is the "correct" way of creating a custom control which can be used in xaml like any other control? If the second way is the correct way - how is it possible to set the style like I do it in a xaml (e.g. every Button in this element has a special style) and has it to be a "global" ResourceDictionary?
How is it implemented in third-party stuff?
Ok I made an example for you, which involves Custom Controls (as Opposed to UserControls)
Step 1:
Create a new class (code only, no XAML) derived from ContentControl (or whatever UI element that has a behavior similar to what you need)
public class ReusableContainer : ContentControl
{
public static readonly DependencyProperty ButtonProperty = DependencyProperty.Register("Button", typeof(Button), typeof(ReusableContainer), new PropertyMetadata(default(Button)));
public Button Button
{
get { return (Button)GetValue(ButtonProperty); }
set { SetValue(ButtonProperty, value); }
}
}
See how I'm defining the Button property as a DependencyProperty here. You can add more DPs for whatever "content placeholders" that you need in your custom control.
Step 2:
Have your predefined Styles for the UI elements inside the container in a separate ResourceDictionary:
CustomStyles.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button">
<Setter Property="Background" Value="Green"/>
</Style>
</ResourceDictionary>
Step 3: in app.xaml, define an application-wide style for the ReusableContainer, which defines it's template:
<Application x:Class="WpfApplication14.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication14"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="{x:Type local:ReusableContainer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ReusableContainer}">
<ControlTemplate.Resources>
<ResourceDictionary Source="CustomStyles.xaml"/>
</ControlTemplate.Resources>
<ContentPresenter Content="{TemplateBinding Button}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
See how I'm using the TemplateBinding expression to define that the ContentPresenter's content is going to be defined by the Button property in the ReusableContainer.
Also notice how I'm Adding the Resources in CustomStyles.xaml to the ControlTemplate.Resources collection. This makes these resources available to all UI elements inside the Template.
Step 4:
Place your ReusableContainer in a Window:
<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication14"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:ReusableContainer>
<local:ReusableContainer.Button>
<Button x:Name="Button1" Content="Hello! Button 1"/>
</local:ReusableContainer.Button>
</local:ReusableContainer>
<local:ReusableContainer>
<local:ReusableContainer.Button>
<Button x:Name="Button2" Content="Hello! Button 2"/>
</local:ReusableContainer.Button>
</local:ReusableContainer>
<local:ReusableContainer>
<local:ReusableContainer.Button>
<Button x:Name="Button3" Content="Hello! Button 3"/>
</local:ReusableContainer.Button>
</local:ReusableContainer>
</StackPanel>
</Window>
I want to give a button a flat style programmatically when certain conditions occur.
This question shows how I can set a style to a control programmatically, having already defined it in XAML.
This question shows that a flat button style already exists, so it is not necessary to create one in XAML.
ToolBar.ButtonStyleKey returns a ResourceKey, and the corresponding style is not defined in my window (it's in ToolBar). How do I use it in code to set the style programmatically?
As an alternative, you can try this:
XAML
<Button Name="FlatButton" Width="100" Height="30" Content="Test" />
Code behind
private void Button_Click(object sender, RoutedEventArgs e)
{
FlatButton.Style = (Style)FindResource(ToolBar.ButtonStyleKey);
}
This is a workaround that works. Add a style based on ToolBar.ButtonStyleKey to Window.Resources as follows:
<Window.Resources>
<Style x:Key="MyStyle" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" TargetType="Button" />
</Window.Resources>
Then, in code, refer to it as per first link in this question:
button.Style = this.Resources["MyStyle"] as Style;
I'd prefer to have a code-only solution (no XAML) for this, but this works just as well.
I am in the process of creating a base window class for most of my windows to derive from. Obviously the best solution for this was a separate class, and a style that applies to it.
The issue is that the <Style ../> I have is not being applied when it is in App.Resources. That is, if it's defined in an external ResourceDictionary, and merged into App.xaml's resources, or a local dictionary and merged, or placed inline into App.Resources. The <Style ../> is, however, applied when it is placed into Themes/Generic.xaml.
The problem can be demonstrated without doing anything special at all in the base window, apart from overriding the DefaultStyleKeyProperty.
Below is ThemeWindow:
public class ThemeWindow : Window
{
static ThemeWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ThemeWindow), new FrameworkPropertyMetadata(typeof(ThemeWindow)));
}
}
Here is the very simple <Style ../> I am trying to apply (it makes the Window background red, nothing more):
<Style TargetType="{x:Type testing:ThemeWindow}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type testing:ThemeWindow}">
<Grid>
<Grid.Background>
<SolidColorBrush Color="Red"/>
</Grid.Background>
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The MainWindow that uses ThemeWindow, is simply the following XAML:
<testing:ThemeWindow x:Class="Testing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:testing="clr-namespace:Testing"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="125,83,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</testing:ThemeWindow>
Now, as stated, if you place that Style in its own ResourceDictionary, and include it like this:
<App.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Themes/ThemeWindow.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</App.Resources>
.. it does not work. If you inline the style straight into App.Resources, it does not work.
The only situation I can find it working is to call the ResourceDictionary xaml Generic.xaml, and place it into the Themes/ directory of the application.
I am wondering exactly why this is happening.
My only theory is that when WPF sees a control type, it will head over to Themes, and scan all ResourceDictionarys for the type, then fall back to Generic.xaml and load it. This doesn't explain why it would not load if the <Style /> is available in a merged ResourceDictionary though. Note that it does work if the MergedDictionary is placed into Generic.xaml, for obvious reasons.
I'm perfectly fine with having to merge the ResourceDictionary into Generic.xaml if that's what I have to do. I just want to get down at the technical details as to why it needs to be like this.
Screenshots of this not working / working:
I have a simple workaround that would allow you to set your Style in you app.xaml.
Define your style in app.xaml like this :
<Style x:Key="{x:Type testing:ThemeWindow}" TargetType="{x:Type testing:ThemeWindow}">
And change your ThemWindow to this :
public class ThemeWindow : Window
{
static ThemeWindow()
{
StyleProperty.OverrideMetadata(typeof(ThemeWindow), new FrameworkPropertyMetadata(GetDefautlStyle()));
}
private static Style GetDefautlStyle()
{
if (defaultStyle == null)
{
defaultStyle = Application.Current.FindResource(typeof(ThemeWindow)) as Style;
}
return defaultStyle;
}
private static Style defaultStyle = null;
}
It does not really solve the question, but that would allow you to achieve what you need !
EDIT : Looking at DefaultStyleKey reference, it's clearly stated that it's used for theme style lookup. That explains why it won't find it in app.xaml or any other dictionary. It will only search in Theme dictionaries. So you either have to define your style in a Theme Dictionary, or to use the Style property directly as in the above example.
I come around the following solution already discussed in stackoverflow. it would required to add in the load component when load of the application.
Refer Solution