I have a ResourceDictionary that contains Style definitions for controls used within my application.
All of the styles are applied properly to the controls in the window...but the style in the ResourceDictionary for the window itself is not being applied.
This is the XAML in my ResourceDictionary that contains the style that I want to apply to my window:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Window}">
<Setter Property="Background" Value="#FF121212"></Setter>
<Setter Property="Height" Value="768"></Setter>
<Setter Property="Width" Value="1024"></Setter>
</Style>
<!-- .... -->
</ResourceDictionary>
This is the XAML for the window that I am working with (trying to get this style to apply):
<Window x:Class="TryingStyles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TryingStyles">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/StylesDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="Label1" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="56,14,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TabControl Height="206" HorizontalAlignment="Left" Margin="12,43,0,0" Name="TabControl1" VerticalAlignment="Top" Width="250">
<TabItem Header="TabItem1" Name="TabItem1">
<Grid></Grid>
</TabItem>
</TabControl>
<GroupBox Header="GroupBox1" Margin="268,43,12,12" Width="396"></GroupBox>
</StackPanel>
</StackPanel>
</Window>
It appears that the style for the window is applied when I view the window in the IDE's "Design view" but when I run the application the style is not applied.
Does anyone know what I'm doing wrong?
It appears that there is no proper solution to your problem. TargetType in Styles doesn't manage derived types.
Here are two alternatives :
You can put a key in your style and apply the style to all your Windows.
<!-- Resource file -->
<ResourceDictionary ...>
<Style TargetType="{x:Type Window}" x:Key="WindowDefaultStyle">
<!-- .... -->
</Style>
</ResourceDictionary>
<!-- Window file -->
<Window Style="{DynamicResource ResourceKey=WindowDefaultStyle}">
Or you can use the BasedOn property of the Style.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfApplication1">
<Style TargetType="{x:Type Window}" x:Key="BaseStyle">
<Setter Property="Background" Value="#FF121212"></Setter>
<Setter Property="Height" Value="768"></Setter>
<Setter Property="Width" Value="1024"></Setter>
</Style>
<!-- Inherit from the BaseStyle and define for the MainWindow class -->
<Style TargetType="{x:Type my:MainWindow}" BasedOn="{StaticResource ResourceKey=BaseStyle}" />
</ResourceDictionary>
It's very strange that it works with the designer but not when the application runs.
The problem seems to be the TargetType of your Style. Wpf seems not be able to match the Window class with your derivated class TryingStyles.
Change your TargetType and it will work :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfApplication1">
<Style TargetType="{x:Type my:TryingStyles}">
<Setter Property="Background" Value="#FF121212"></Setter>
<Setter Property="Height" Value="768"></Setter>
<Setter Property="Width" Value="1024"></Setter>
</Style>
<!-- .... -->
</ResourceDictionary>
I'm quite late to the party here, but I found a solution to have Style TargetType="{x:Type Window}" apply to every window application-wide, as one would expect. For the record, the reason this doesn't work is because each window you create is not a Window but a new type that derives from window (e.g. "MainWindow"), and Style's TargetType doesn't apply to derived classes. Anyway:
First, ensure your App.xaml has a Startup property defined; so inside the <Application> tag you'd add Startup="Application_Startup" or whatever you want to call the startup method.
Then, inside App.xaml.cs add:
private void Application_Startup(object sender, StartupEventArgs e)
{
FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
{
DefaultValue = Application.Current.FindResource(typeof(Window))
});
}
where the method name matches whatever you listed as the Startup property in App.xaml. And of course, if you already have an existing startup method being run, just add the code contained within to that.
This basically just fixes it so that keyless Styles targeting "Window" will apply their changes to every window in your application, as you probably expected would occur without this code snippet. (That is of course assuming your style is already scoped application-wide, for example by containing it within a ResourceDictionary that is merged into App.xaml.)
Related
I am creating a collection of custom controls in a project MyLibrary.UI. What I want to achieve is to define the some properties in a component that can be customize in every main app that uses MyLibrary.UI.
I wanto to make an example of customizing an Icon in the control FilteredComboBox.
I tried two ways:
I added a DependencyProperty FindImage defined in FilteredComboBox.cs:
public class FilteredComboBox : ComboBox
{
...
#region FindImageProperty
public static readonly DependencyProperty FindImageProperty = DependencyProperty.Register(
nameof(FindImage), typeof(BitmapImage),
typeof(FilteredComboBox),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
DefaultValue = new BitmapImage(new Uri("pack://application:,,,/MyLibrary.Icons;component/Icons/Find.png"))
});
public BitmapImage FindImage
{
get
{
return (BitmapImage)GetValue(FindImageProperty);
}
set
{
SetValue(FindImageProperty, value);
}
}
#endregion FindImage
static FilteredComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FilteredComboBox), new FrameworkPropertyMetadata(typeof(FilteredComboBox)));
}
...
}
and modified the style FilteredComboBoxStyle.xaml as below:
<ControlTemplate x:Key="FilteredComboBoxTemplate" TargetType="{x:Type local:FilteredComboBox}">
...
<DockPanel>
<Image Source="{TemplateBinding FindImage}" Width="25" Height="25" DockPanel.Dock="Left"/>
<TextBox x:Name="PART_SearchTextBox" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SearchText, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" DockPanel.Dock="Left"/>
</DockPanel>
...
</ControlTemplate>
<Style TargetType="{x:Type local:FilteredComboBox}" x:Key="baseFilteredCBStyle">
...
<Setter Property="Template" Value="{StaticResource FilteredComboBoxTemplate}"/>
...
</Style>
<Style TargetType="{x:Type local:FilteredComboBox}" BasedOn="{StaticResource baseFilteredCBStyle}"/>
Then I added the reference of this control style in Themes/generic.xaml and I defined in the resources of App.xaml of my application the following style:
<Style TargetType="{x:Type local:FilteredComboBox}" BasedOn="{StaticResource baseFilteredCBStyle}">
<Setter Property="FindImage">
<Setter.Value>
<BitmapImage x:Key="myImage" Source="pack://application:,,,/MyCustomApp.Icons;component/Icons/Find.png"/>
</Setter.Value>
</Setter>
</Style>
I would expect that this would change the icon with MyCustomApp.Icons, but it still keeps the Icon in MyLibrary.Icons.
Then I tried to use a DynamicResource to set the image, so in FilteredComboBoxStyle.xaml:
<BitmapImage x:Key="myImage" Source="pack://application:,,,/MyLibrary.Icons;component/Icons/Find.png"/>
<ControlTemplate x:Key="FilteredComboBoxTemplate" TargetType="{x:Type local:FilteredComboBox}">
...
<DockPanel>
<Image Source="{DynamicResource myImage}" Width="25" Height="25" DockPanel.Dock="Left"/>
<TextBox x:Name="PART_SearchTextBox" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SearchText, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" DockPanel.Dock="Left"/>
</DockPanel>
...
</ControlTemplate>
<Style TargetType="{x:Type local:FilteredComboBox}">
...
<Setter Property="Template" Value="{StaticResource FilteredComboBoxTemplate}"/>
...
</Style>
Then in the resources of App.xaml:
<BitmapImage x:Key="myImage" Source="pack://application:,,,/MyCustomApp.Icons;component/Icons/Find.png"/>
With this approach my application shows the icon from MyCustomApp.Icons.
My questions are:
Why the option 1 is not working? There is something wrong with it?
Is the option 2 the proper way to customize the custom controls to be application-specific?
I made an example with an Image but could be any property of a control.
The Themes/generic.xaml resource dictionary should be located in the project where the custom control is defined.
If you want to set the FindImage property using an implicit style in the consuming application, you should put the Style in App.xaml or in a resource dictionary that is merged into App.xaml:
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...>
<Application.Resources>
<ResourceDictionary>
<Style TargetType="{x:Type local:FilteredComboBox}" BasedOn="{StaticResource baseFilteredCBStyle}">
<Setter Property="FindImage">
<Setter.Value>
<BitmapImage Source="pack://application:,,,/MyCustomApp.Icons;component/Icons/Find.png"/>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
Your question is very difficult because it is full of typos and compiler errors. It's hard to tell where you did wrong and where you were just sloppy when creating the example. Maybe you should create the question more carefully next time.
Option 1 is not working because you can't reference a resource defined in Generic.xaml from your application. Generic.xaml is meant as a theme dictionary for theme resources, like the default control Style of FileteredComboBox.
This means you can't base a Style defined in App.xaml on an explicitly named resource that is defined in Generic.xaml.
Option 2 is working because there is no such an illegal reference to a resource that is defined in Generic.xaml. The Style in Generic.xaml references a resource (the BitmapImage) using the DynamicResource markup. The lookup behavior of this markup (opposed to StaticResource) occurs at runtime: once the application is running, lookup starts from the location of the referencing element and traverses up the logical tree to visit every ResourceDictionary along the route. Then the XAML engine checks the App.xaml and finally Generic.xaml for the requested resource.
In your particular case the lookup starts directly at App.xaml, where the XAML engine successfully finds the BitmapImage with the matching key.
To fix your issue, you must base the Style defined within the application scope on the target type (which will implicitly translate to the default Style of the styled control):
BasedOn="{StaticResource {x:Type local:FilteredComboBox}}"
App.xaml
<Style TargetType="{x:Type local:FilteredComboBox}"
BasedOn="{StaticResource {x:Type local:FilteredComboBox}}">
<Setter Property="FindImage">
<Setter.Value>
<BitmapImage x:Key="myImage"
Source="pack://application:,,,/MyCustomApp.Icons;component/Icons/Find.png" />
</Setter.Value>
</Setter>
</Style>
I have to point out that it is not necessary to base your Style on the default Style explicitly.
The default Style is always loaded first. Any additional Style that targets the same control will be applied commulative i.e it will be "merged" into the default style: unless FrameworkElement.OverridesDefaultStyle is set to true, only the duplicate property setters are overwritten. Otherwise the default Style will be completely ignored (overridden).
In other words, application scope styles are always implicitly based on the control's default Style.
File: App.xaml
<Application x:Class="MyApp.App">
<Application.Resources>
<ResourceDictionary Source="Themes/Dark.xaml"/>
</Application.Resources>
</Application>
File: Dark.xaml
<ResourceDictionary>
<SolidColorBrush x:Key="Background.Primary">Red</SolidColorBrush>
</ResourceDictionary>
File: Main.xaml
<Window>
<Window.Resources>
<Style TargetType="local:Main">
<Setter Property="Background" Value="{DynamicResource Background.Primary}"/>
</Style>
</Window.Resources>
</Window>
File Structure:
Root
App.xaml
Main.xaml
Themes
Dark.xaml
In designer I can notice that the background of my main window turns red, but when I compile the project the background is just transparent !!!
When you add an implicit Style to the Resources dictionary of a window, it will be applied to all children of the window with a matching type.
But the Main window is not a child of itself obviously.
You should set the Style property rather than adding the Style to Resources:
<Window>
<Window.Style> !!! <--
<Style TargetType="local:Main">
<Setter Property="Background" Value="{DynamicResource Background.Primary}"/>
</Style>
</Window.Style>
</Window>
Alternatively, you could just set the Background property directly:
<Window ... Background="{DynamicResource Background.Primary}" />
If it is necessary to set window background try:
<Window ... >
<Window.Background>
<StaticResource ResourceKey="Background.Primary" />
</Window.Background>
...
</Window>
or this works as well:
<Window ...
Background="{StaticResource Background.Primary}">
...
</Window>
I am attempting to make a ResourceDictionary of some standardised colour schemes etc to add to a dll class library for use in future applications. I am new to XAML and seem to have made an error when it comes to creating or using the content setter part of the dictionary. I cannot set and use the colour of the text in the dictionary. Here is what I have so far; As you can see, the Foreground of the TextBlock in the Content is set to White.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:My_Class_Library.WPF_Resources">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../WPF Resources/Buttons.xaml"/>
<ResourceDictionary Source="../WPF Resources/Brushes.xaml"/>
<ResourceDictionary Source="../WPF Resources/Sliders.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="myButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button" >
<Grid>
<Rectangle Name="ClickFill" Fill="ForestGreen" RadiusX="5" RadiusY="5"/>
<ContentPresenter RecognizesAccessKey="True" Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Content">
<Setter.Value>
<Grid>
<TextBlock Background="{x:Null}" Foreground="White"></TextBlock>
</Grid>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and here's the reference to the dictionary:
<Grid x:Class="My_Class_Library.Update_Information"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:My_Class_Library"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../WPF Resources/Buttons.xaml"/>
<ResourceDictionary Source="../WPF Resources/Brushes.xaml"/>
<ResourceDictionary Source="../WPF Resources/Sliders.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Grid.Resources>
<Button Name="Click"
Width="100" Height="30"
Style="{StaticResource myButton}"
Click="Click_Click">
_click
</Button>
</Grid>
however, what I see is this:
, which as you can see has black (presumably default) text instead of the specified white. What am I doing wrong, that causes the content not to be set?
I know everybody hates questions like "look at this, what's wrong with it?" but I am at my wit's end trying to find a solution - I am following loads of training videos and so on and the above is my best effort... Nearly everything else I try breaks the whole thing! Any pointers very appreciated!
You've kind of got the right idea but you'll want to get used to setting properties from the style template as setter directly. I'd also suggest you start with a default style template of a control and edit it to your needs since like for instance in this case you're going to lose all of the additional Visual states for things like MouseOver etc.
However for the sake of your immediate question, you're going to ditch your Content property all together from the template (that's your ContentPresenter job) and instead just do this (in pseudo);
<Style x:Key="myButton" TargetType="Button">
<Setter Property="Foreground" Value="White"/>
<!-- Rest of it goes here -->
</Style>
...and voila. Hope this helps, cheers!
I have an application with a large number of styles that are currently duplicated in the .xaml for each window of the application. I would like to be able to reference one file called UiStyles.xaml that contains all of the styles for the application.
After reading a ton of answered questions on here and Google I've tried this:
ButtonStyle.xaml:
<Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
<Setter Property="Background" Value="Red"/>
<Setter Property="FontSize" Value="48"/>
</Style>
</ResourceDictionary>
UiStyles.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ButtonStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Control" /> <!-- Added this based on other user's suggestions to account for .net 4 bug -->
</ResourceDictionary>
MainWindow.xaml:
<Window x:Class="TestingGround.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary Source="Resources/UIStyles.xaml"/>
</Window.Resources>
<Grid>
<Button Click="ButtonBase_OnClick" Content="Test Text"/>
</Grid>
</Window>
But my button style is not being applied! What am I doing wrong?
Note when you apply a key to a style, you have to explicitly apply it to the control so
<Button Click="ButtonBase_OnClick"
Content="Test Text"
Style={StaticResource ButtonStyle} />
However if you want all buttons to default to the style remove the x:key="ButtonStyle".
<Style TargetType="...">
You have created your button style with an x:Key, but are not referencing that in your button instance.
You need to set the "Style" property of the button like so:
<Button Click="ButtonBase_OnClick" Style="{StaticResource ButtonStyle}" Content="Test Text"/>
I'm totally new on WPF and I need your help for creating a wpf custom ListBox with scrollbar wider than the default.
I've found a solution that works fine for a Window WPF including a ListBox:
<Window x:Class="iFixCustomControlsTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:iFixCustomControls;assembly=iFixCustomControls"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox HorizontalAlignment="Left" Height="92" Margin="56,88,0,0" VerticalAlignment="Top" Width="357" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
</Grid>
<Window.Resources>
<Style TargetType="ScrollBar">
<Setter Property="Width" Value="100"/>
</Style>
</Window.Resources>
</Window>
This solution is not the my favorite one, because it implies to write code in a Window including a "classic" Listbox. What I need is a way to modify scrollbar inside the Listbox (if I understood fine) in Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:iFixCustomControls">
<Style TargetType="local:iFixCustomListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<!--
Setting scrollbar wider than default
Something like:
<Style TargetType="ScrollBar">
<Setter Property="Width" Value="100"/>
</Style>
-->
</Style>
</ResourceDictionary>
.cs file is:
public class iFixCustomListBox : ListBox
{
static iFixCustomListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(iFixCustomListBox), new FrameworkPropertyMetadata(typeof(iFixCustomListBox)));
}
}
Is this approach correct or a better way should involve User Control instead Custom Controls?
If I understand you correctly you have a custom control type derived from ListBox and you want every instance of that control to have a wider vertical scrollbar.
If so, you can just use a custom style for your control (which you probably have already), and add a ScrollBar style to that style's Resources collection:
<Style TargetType="{x:Type local:iFixCustomListBox}">
<Style.Resources>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Width" Value="100" />
</Style>
</Style.Resources>
</Style>
I tried with this style placed in the resources collection of (a) a window, and (b) the application, and it worked fine in both cases, so I assume it would also work if placed in generic.xaml.
What about this?
<ScrollViewer Width="100">
<ListBox ...>
</ScrollViewer>