Setting button flat style programmatically - c#

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.

Related

Vertically Centering MenuItem text in a Fluent Ribbon with C# WPF

I'm working with Fluent.Ribbon, and I am desperately trying to vertically center the text of second level menu items. I actually wouldn't mind making second level have the same style as first level items if that would be easier.
From digging through the source code, I think I've found that the separate style is defined by the ControlTemplate ApplicationMenuSecondLevelItemTemplate. However, since I'm working on learning WPF, I'm not sure how to override that with styles.
I've tried simpler solutions, like this one which just makes the text disappear.
I've also tried all of the option in this post. However, none of those work either, and when I fix the last one to be the following to get rid of errors, the application just crashes.
<Style x:Key="CenteredTextMenuItem" TargetType="{x:Type MenuItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Text="{Binding}" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center" FontSize="16" FontWeight="Bold"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Height" Value="30"/>
<Setter Property="Width" Value="188"/>
</Style>
How can I center a second level MenuItem's text with the Fluent.Ribbon control?
Thanks.
Edit:
Here is an image showing how the second level is not centered.
And nothing complicated with the code:
<Fluent:MenuItem Header="Print Invoice" Icon="NavIcons\Print_32.png" />
Here are possible solutions for your problem.
Simple, but somewhat ugly.
Create an event handler in code behind for the Loaded event of your menu items.
<Fluent:MenuItem Loaded="MenuItem_Loaded"/>
In this event handler, you can find the control template parts manually and override their appearance:
private void MenuItem_Loaded(object sender, RoutedEventArgs e)
{
Fluent.MenuItem menuItem = sender as Fluent.MenuItem;
if (menuItem != null)
{
TextBlock textBlock = menuItem.Template.FindName("textBlockDesc", menuItem) as TextBlock;
if (textBlock != null)
{
textBlock.Visibility = System.Windows.Visibility.Collapsed;
}
textBlock = menuItem.Template.FindName("textBlock", menuItem) as TextBlock;
if (textBlock != null)
{
textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Center;
}
}
}
This is a bad solution, don't do it like that. I've just shown it so you can get an idea how could you access the template parts if you wish to. These strings "textBlockDesc" and "textBlock" are the control template parts defined in the Fluent theme.
Create your own style and control template.
Since you can't inherit a control template, you have to copy it from the Fluent theme and put it in your resources. The disadvantage is that you'll have to manually resync that template with the original one if there will be an update.
I don't put an example here, because that solution isn't really good too.
Override the menu item style manually.
Set the style of your menu items manually to the "first level" menu items' style.
<Fluent:MenuItem Style="{DynamicResource ApplicationMenuStyle}"/>

WPF - Focus Control Within DataTemplate applied to FlyoutControl

I have a DataTemplate which contains a TextBox. The DataTemplate is bound to the ContentTemplate property of a Style for the DevExpress FlyoutControl. The Flyout Control itself is within the ControlTemplate of another TextBox.
When the TextBox with the FlyoutControl is focused, I want to redirect focus to the first TextBox in the FlyoutControl's ContentTemplate (from the DataTemplate). Setting FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}} on the TextBox I want focused accomplishes this the first time, but once the Flyout has loaded it no longer works.
I have tried every suggestion I can find and nothing so far has worked. I can get the TextBox I want to reference in code and call Focus(), but it always returns false. At best, when I try to focus it in code, the Flyout is focused instead, but never the TextBox within the Flyout.
Here is what each relevant part looks like (irrelevant code omitted):
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit x:Name="TextThatWantsFocus"
FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}}" />
</Grid>
</DataTemplate>
...
<Style x:Key="FlyoutStyle" TargetType="dxe:FlyoutControl">
<Setter Property="ContentTemplate" Value="{StaticResource FlyoutTemplate}"/>
</Style>
...
<dxe:TextEdit>
<dxe:TextEdit.Template>
<ControlTemplate>
<StackPanel>
<dxe:TextEdit x:Name="InnerTextEdit" />
<dxe:FlyoutControl Style="{StaticResource FlyoutStyle}"/>
</StackPanel>
</ControlTemplate>
</dxe:TextEdit.Template>
</dxe:TextEdit>
The flyout is being opened in code. It is here that I also would like to focus the TextBox (TextThatWantsFocus). However, nothing I have tried will give it focus (except for FocusManager handling it the first time), including the typical SO answer involving triggers. Any ideas would be greatly appreciated.
I took DmitryG's advice and submitted a DevExpress support ticket, and they were able to provide a solution.
The issue was resolved by handling the Loaded event of the TextEdit I want focused and using the dispatcher to focus it:
private void TextThatWantsFocus_Loaded(object obj, RoutedEventArgs e)
{
var text = obj as FrameworkElement;
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(delegate()
{ text.Focus(); }));
}
I suggest you using the FocusBehavior from DevExpress MVVM Framework:
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit>
<dxmvvm:Interaction.Behaviors>
<local:FocusBehavior/>
</dxmvvm:Interaction.Behaviors>
</dxe:TextEdit>
</Grid>
</DataTemplate>

What's the correct way to create a custom control

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>

WPF Style for base window not applied in App.xaml, but is in Themes/Generic.xaml

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

Disable Style in WPF XAML?

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"];

Categories

Resources