WPF Default DynamicRessource values - c#

Is there a way to save a default value for dynamic ressources in a custom control library?
I have created a custom control library and therefore I use a default Style which resides in the Generic.xaml file. This "default style" uses references to dynamic resource markers (see in the example).
<Style TargetType="{x:Type local:BorderlessWindow}">
<Setter Property="Foreground" Value="{DynamicResource ForegroundColor}" />
<Setter Property="Background" Value="{DynamicResource BackgroundColor}" />
<Setter Property="TitleBackground" Value="{DynamicResource AltBackgroundColor}" />
<Setter Property="Template" Value="{StaticResource DefaultBoderlessWindowTemplate}" />
</Style>
Everything is working as expected if I reference to my custom control library in a new project and add the dynamic resource markers in this new projects app.xaml but the values are empty if I do not do this.
So I want some kind of default values. In other words:
"Take the value of {DynamicResource ForegroundColor} or if this do not exist blue."
I thought I just have to add the default values in the Generic.xaml (MergedDictionary) but this wont do the job. Does anyone have a solution?
The only solution I can think about is to replace the dynamicResource markers with the concret (default) values (e.g. blue, green, black) and handle resources in the "consuming" app if you know what I mean.

After InitializeComponent you can see if the resource you need is found and add a default if not.
public MainWindow()
{
InitializeComponent();
try
{
var resource = FindResource("ForegroundColor");
}
catch (ResourceReferenceKeyNotFoundException)
{
Resources.Add("ForegroundColor", new SolidColorBrush(Colors.Red));
}
}

you are on a complex problem
see that
https://wangmo.wordpress.com/2007/09/27/themesgenericxaml/
Why is my style in Generic.xaml not working?
take care how you define your controldefault style
the place where you put themes\generic.xaml
where did you include your color scheme (normaly in generic)
check assemblyinfo
etc
if all is well structured, it must take your default color in the custom control assembly
or simply just include your generic from assembly in the app.xaml
<ResourceDictionary Source="pack://application:,,,/Client.Core;Component/themes/generic.xaml"/>

Related

WPF - Can only base on a Style with target type that is base type

This is sending me nuts, mostly because at runtime it works perfectly (the problem only appear at design time), but I decided to ask anyway as I'm working on a big project and I want to implement things the best way.
First thing: I have a component from a third part library, it is basically like a border, and it's defined this way (with F12):
public class AdvancedBorder : ContentControl
I like the visual aspect of this thing, but I need to add some functionalities. So I created a new Custom Control:
public class SelectableCard : AdvancedBorder
{
// bunch of custom properties and stuff
static SelectableCard()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SelectableCard), new FrameworkPropertyMetadata(typeof(SelectableCard)));
}
}
Finally I need to keep the exactly same visual but adding some triggers, so I put this in generic.xaml:
<Style TargetType="{x:Type customControls:SelectableCard}" BasedOn="{StaticResource ResourceKey={x:Type otherLibrary:AdvancedBorder}}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Style.Triggers>
<Trigger Property="customControls:SelectableCard.IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource MyLightBrush}" />
</Trigger>
</Style.Triggers>
</Style>
customControls is the xmlns for my namespace, otherLibrary is the xmlns for the third part library.
Everything works perfectly fine at runtime, and gives no errors at all. At design time I get no errors from the generic.xaml, but as soon as I put the SelectableCard in some xaml file, I get
Can only base on a Style with target type that is base type
SelectableCard
And I don't get it at all, especially as it works at runtime. I can remove the BasedOn attribute and I get no more complaints at design time, but then I have to add the setter for the template otherwise I can't see anything at runtime.
What am I doing wrong, here?

Change the control property globally in wpf

I have a back button which is copied almost to all the Controls in my application.
I have set the styles and properties of the button on each individual control (usercontrol)
Now I want to change the text property of the button of all the control (usercontrol).
I don't want to go and change the property of each control.
Please help me setting a global property which sets the property in one place.
Since the style is common to all pages. Create the style without a key/name, just the target type would do.
<Style TargetType="{x:Type Button}">
Then do either of the following -
Add it to the App.XAML for visibility throughout the app
Better approach would be to define a resource dictionary file and import it, wherever you need it.
<Style TargetType="{x:Type Button}">
<Setter Property="Text" Value="{Binding text}" />
<Setter Property="...." Value="{Binding ....}"/>
</Style>
Add this to App.xaml file as you want it to be global style for all your user controls.

WPF: Dynamically change dependency property value for all user controls of same type

I'm rather new to WPF and encountered some difficulties with user controls.
Please consider the following scenario:
I have a WPF application with a user control, say
MySpecialButtonControl
This "button" has two appearances "oldStyle" and "newStyle" (specified by the Enum "AppearanceStyle") which are controlled by a dependency property with the name
MyLayoutProperty
The callback function has to carry out the code which changes the layout.
Now here is what I would like to do:
I need to change the appearance of all (!) instances of the user control in this window at once in a code-behind file at run-time.
Binding (e.g.) a property to individual instances of the UC like
Binding binding = new Binding("AppearanceStyle");
binding.Source = myOptionsClass;
this.myButton.SetBinding(UserControls.MySpecialButtonControl.MyLayoutProperty, binding);
works perfectly well. But how can I directly change the dependency property for ALL UC instances without having to iterate over collections of the UCs, etc.? Is there even a way to achieve this in WPF/C#?
I tried to solve this problem by using styles, but changing the style which is shared by all UCs itself at runtime is not possible since it is already in use (and the UCs which use this style have already been drawn).
Next, I tried to use a dynamic resource in the style like this:
<uc:MySpecialButtonControl x:Key="myFakeButton" ></uc:MySpecialButtonControl >
<Style x:Key="myButtonStyle" TargetType="uc:MySpecialButtonControl ">
<Setter Property="MyLayoutProperty" Value="{DynamicResource myFakeButton}"></Setter>
</Style>
This allows me to change the "MyLayoutProperty" for "myFakeButton" at runtime which is half of what I want, but even after googling for some time I still could not find a way to bind the "MyLayoutProperty" of "myFakeButton" to the setter which is what I really need.
Any help would be greatly appreciated!
Update:
I tried to implement the solution provided by Michael, but unfortunately, I got the following exception:
PropertyMetadata is already registered for type 'MySpecialButtonControl'.
After some googling (see MSDN) I found that the OverrideMetadata call should be placed in a static constructor of "MySpecialButtonControl" which I did:
static MySpecialButtonControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(MySpecialButtonControl),
new FrameworkPropertyMetadata(typeof(MySpecialButtonControl)));
}
Now, the application compiles. And now it works perfectly.
I'm not entirely sure I follow, but I'll attempt an answer. Please comment if this is close, and I'll edit until we get there.
All controls in WPF have a property DefaultStyleKey. Any derived custom control or user control can use this property to set the key of the default style. At runtime, the framework will try to find a resource of this key. It is common to set the default style key equal to the runtime type of the class.
public MySpecialButtonControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof (MySpecialButtonControl),
new FrameworkPropertyMetadata(typeof (MySpecialButtonControl)));
InitializeComponent();
}
When a control placed onto a Window, the framework will look in the available resources for a resource with the key that is defined by DefaultStyleKey. The resource can be defined in a number of places. Google "WPF resource resolution" for more info. The simplest way to illustrate is to show the default style defined in your App.xaml.
<Application.Resources>
<!-- the default style for MySpecialButtonControls -->
<Style x:Key="{x:Type uc:MySpecialButtonControl}"
TargetType="{x:Type uc:MySpecialButtonControl}"
BasedOn="{StaticResource {x:Type UserControl}}" >
<Setter Property="Background" Value="Blue" />
</Style>
</Application.Resources>
Now suppose you have two different styles that you want to switch between at runtime. You might define those styles in your App.xaml.
<Application.Resources>
<!-- the first style -->
<Style x:Key="Style1"
TargetType="{x:Type uc:MySpecialButtonControl}"
BasedOn="{StaticResource {x:Type UserControl}}">
<Setter Property="Background" Value="Blue" />
</Style>
<!-- the second style -->
<Style x:Key="Style2"
TargetType="{x:Type uc:MySpecialButtonControl}"
BasedOn="{StaticResource {x:Type UserControl}}">
<Setter Property="Background" Value="Red" />
</Style>
<!-- the default style, now based on Style1 -->
<Style x:Key="{x:Type uc:MySpecialButtonControl}"
TargetType="{x:Type uc:MySpecialButtonControl}"
BasedOn="{StaticResource Style1}" />
</Application.Resources>
At runtime, you could do something like this to toggle the default style of the controls.
private void Button_Click(object sender, RoutedEventArgs e)
{
// get the style resources
var style1 = FindResource("Style1") as Style;
var style2 = FindResource("Style2") as Style;
var defaultStyle = FindResource(typeof (MySpecialButtonControl)) as Style;
if (style1 == null || style2 == null || defaultStyle == null)
return;
// create a new style based on the "other" style
var newDefaultStyle = new Style(
typeof (MySpecialButtonControl),
(defaultStyle.BasedOn == style1 ? style2 : style1));
// set the application-level resource to the new default style
Application.Current.Resources[typeof (MySpecialButtonControl)] = newDefaultStyle;
}
Is this even close?

Cannot find a Resource with the Name/Key

I'm trying to unit test a user interface using the Silverlight 4 Toolkit.
When I attempt to instantiate the UserControl, it's throwing an exception because in the XAML of the UserControl it's using a Style defined App.xaml.
Is there a way to load the resource somehow before I instantiate the UserControl? Am I going about this the wrong way?
Here's the unit test code:
[TestMethod]
public void ExerciseTimePeriodUserInterface()
{
CustomUserControls.TimePeriodFilter timePeriodFilter = new CustomUserControls.TimePeriodFilter();
}
Here's the reference to the style in the UserControl:
<Border Style="{StaticResource FilterBorderWrapper}">
And lastly, here's the style defined in the App.xaml:
<Style TargetType="Border" x:Key="FilterBorderWrapper">
<Setter Property="Background" Value="#F1F5FB" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#CBD9E9" />
<Setter Property="CornerRadius" Value="2" />
<Setter Property="Margin" Value="2" />
</Style>
If all your resources placed into ResorceDictionaries. You can simple create Application instance and add that Dictionary to the resources. Please look at the sample:
Application _app = new Application();
ResourceDictionary dictionary = new ResourceDictionary();
dictionary.Source = new Uri("pack://application:,,,/Gui.Mvvm;component/Themes/YourResourceDictionary.xaml");
_app.Resources.MergedDictionaries.Add(dictionary);
For my WPF app this works fine. After this code was written I was able to test my Template Selectors, DataTemplate Selectors and so forth. All code using in codebehind calls to
Application.Current.FindResource()
works quite good.
You can't easily unit test User controls out of context. Too many dependencies.
You can test your view models with unit tests (which should be where all your code is anyway) and the Silverlight controls with some form of GUI automation (or humans if you can't afford the latest GUI test tools).
As VC 74 implied, if you are not already using MVVM, you probably should (if you want to do Silverlight unit testing).
Rick,
basically, I was getting the same error. Later then, i simply copied the Resources and all definitions to the Test-Projects App.xaml file (I also have a Styles.xaml resource), and my UI Tests work without problems.
Of course, it's never the best solution to copy "anything", but hey, I really don't care about the styles. Plus, you could even define own styles for the UI Testing Panel.
HTH
Thomas

WPF Updating styles at runtime

I would like to update the default Window style dynamically at runtime so I can change the FontSize and FontFamily dynamically at runtime. I found that Styles in your resource dictionary are sealed at runtime and cannot be changed, so I used the following method of updating the style:
<Style TargetType="{x:Type Window}">
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontSize" Value="12pt"/>
</Style>
With the following code:
Style newStyle = (Make a copy of the old style but with the FontSize and FontFamily changed)
// Remove and re-add the style to the ResourceDictionary.
this.Resources.Remove(typeof(Window));
this.Resources.Add(typeof(Window), newStyle);
// The style does not update unless you set it on each window.
foreach (Window window in Application.Current.Windows)
{
window.Style = newStyle;
}
There are several problems with this approach and I have a few questions as to why things are the way they are.
Why are styles sealed at runtime and is there a way of making them unsealed?
When I re-add the new style, why is this not picked up by all of my windows? Why do I have to go and manually apply it to every window?
Is there a better way?
I would probably tackle this with a "settings service" which exposes properties for the various settings, and fires INPC as you would for normal binding. Next up I'd change that style to be something like:
<Style x:Key="MyWindowStyle">
<Setter Property="FontFamily" Value="{Binding Path=FontFamily, Source={StaticResource SettingsService}, FallbackValue=Arial}"/>
<Setter Property="FontSize" Value="{Binding Path=FontSize, Source={StaticResource SettingsService}, FallbackValue=12}"/>
</Style>
With your "settings service" defined as a static resource:
<services:SettingsService x:Key="SettingsService"/>
Then in each window make sure the style is set as a DynamicResource:
<Window Style="{DynamicResource MyWindowStyle}" .... >
There is often a lot of misunderstanding around the differences between Static and Dynamic resources, but the basic difference is Static is a "one time" setting whereas Dynamic will update the settings if the resource changes.
Now if you set those properties in your "settings service" they will fire INPC, which will update the Style, which the DynamicResource will pick up on and alter the Window properties accordingly.
Seems like a lot of work, but it gives you some nice flexibility, and all the "heavy lifting" is done purely using Bindings. We use a similar technique on a project I'm working on at the moment so when a user chooses a fill/stroke colour the various tools in the toolbar update to reflect the new values.

Categories