Change the control property globally in wpf - c#

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.

Related

WPF Default DynamicRessource values

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"/>

How to work with control inheritance

I use Telerik as a WPF library. We can apply a theme on Telerik controls using application Theme (i.e. theme manager). For Microsoft controls we can set a property to make the theme apply.
The problem is : I don't want to write this line :
<Style TargetType="{x:Type CheckBox}">
<Setter Property="telerik:StyleManager.Theme" Value="{Binding Source={StaticResource Settings}, Path=Default.Theme}" />
</Style>
for every type: CheckBox, TextBlock, TextBox etc.. for maintenance purpose.
If I target <Style TargetType="{x:Type Control}"> inheritance doesn't work well.
Base class of CheckBox is Control but when I set property on every control it doesn't set property on every child of control too. Any idea how i can do this?

Border thickness for Telerik's RadMaskedInputBaseStyle in Silverlight when content is invalid

How do I increase border thickness for RadMaskedInputBaseStyle (or RadMaskedDateTimeInput by Telerik) in Silverlight only WHEN it is red indicating that the input contains invalid entry.
My XAML looks like this
<Style TargetType="telerik:RadMaskedDateTimeInput">
<Setter Property="IsValidationHintVisible" Value="True" />
</Style>
In general, if a style isn't available as a property of the control, then you will find it buried somewhere in the control template (as Chris W alludes to in the comments).
To see the source for a proprietary control template like one of Telerik's, open up Expression Blend and click "Edit Template" on an instance of the control. If you do that for the RadMaskedDateTimeInput, you will notice the validation-related visual states making reference to an element named "ErrorElement". Scroll down, in the control template source, and you will see that is declared as follows:
<Telerik_Windows_Controls_Chromes:ValidationTooltip x:Name="ErrorElement" Opacity="0" TooltipPlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" telerik:StyleManager.Theme="{StaticResource Theme6}" TooltipContent="{TemplateBinding DisplayErrorMessage}" TooltipContentTemplate="{TemplateBinding ErrorMessageTemplate}" />
Ok, so it's another control called ValidationTooltip. This control does have a BorderThickness property exposed, so if you like, you should be able to simply set that property in a targeted global style. Something like this should go in your resource dictionary:
<Style xmlns:Telerik_Windows_Controls_Chromes="clr-namespace:Telerik.Windows.Controls.Chromes;assembly=Telerik.Windows.Controls"
TargetType="Telerik_Windows_Controls_Chromes:ValidationTooltip">
<Setter Property="BorderThickness" Value="2" />
</Style>

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?

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