views:

752

answers:

1

Suppose that you are developing a custom control in WPF that contains internally some other basic controls. To keep it simple suppose that it contains 2 buttons.

Now you want to use this custom control in your app, but you want to restyle it a bit.

CASE 1

If, in the custom control definition, both buttons have the same style (wpf default) and you want to restyle both, it should be easy:

<mc:MyControl>
   <mc:MyControl.Resources>
      <Style x:Key={x:Type Button}, TargetType={x:Type Button}>
         <!-- Insert the new style here -->
      </Style>
   </mc:MyControl.Resources>
<mc:MyControl>

CASE 2

If, in the custom control definition, both buttons have the same style (wpf default) but you want to restyle them with two different styles, what's the best way to solve it?

CASE 3

If, in the custom control definition, both buttons have the same style, that refer to a Style defined inside the custom control, and you want to restyle them, what's the best way to solve it?

Thank you in advance for all help

+3  A: 

You could define 2 different Style properties in your custom control and bind them to the Style property of the individual buttons, thus allowing clients to set the style for the two controls independently of each other.

XAML file:

<UserControl x:Class="MyNamespace.MyControl"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Name="MyControl">
  <StackPanel>
    <Button Name="FirstButton"
            Style={Binding ElementName=MyControl, Path=FirstButtonStyle}
            Content="First Button" />
    <Button Name="SecondButton"
            Style={Binding ElementName=MyControl, Path=SecondButtonStyle}
            Content="Second Button" />
  </StackPanel>
</UserControl>

Code-behind file:

using System;
using System.Windows;
using System.Windows.Controls;

namespace MyNamespace
{
  [StyleTypedProperty(
  Property = "FirstButtonStyle",
  StyleTargetType = typeof(Button))]
  [StyleTypedProperty(
  Property = "SecondButtonStyle",
  StyleTargetType = typeof(Button))]
  public partial class MyControl : UserControl
  {
    public static readonly DependencyProperty FirstButtonStyleProperty =
      DependencyProperty.Register(
        "FirstButtonStyle",
        typeof(Style),
        typeof(MyControl)
      );

    public Style FirstButtonStyle
    {          
      get { return (Style)GetValue(FirstButtonStyleProperty); }
      set { SetValue(FirstButtonStyleProperty, value); }
    }


    public static readonly DependencyProperty SecondButtonStyleProperty =
      DependencyProperty.Register(
        "SecondButtonStyle",
        typeof(Style),
        typeof(MyControl)
      );

    public Style SecondButtonStyle
    {          
      get { return (Style)GetValue(SecondButtonStyleProperty); }
      set { SetValue(SecondButtonStyleProperty, value); }
    }
  }
}

It is a good idea to implement these 2 properties as dependency properties, since that will make them conform to the other Style properties in standard WPF controls.

Now you can set the style for the buttons like you would in any WPF control:

<Window 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:local="clr-namespace:MyNamespace"
  Title="MyControl Sample" 
  Height="300" 
  Width="300">
  <Window.Resources>
    <Style x:Key="GreenButton" TargetType="{x:Type Button}">
      <Setter Property="Background" Value="Green" />
    </Style>
    <Style x:Key="RedButton" TargetType="{x:Type Button}">
      <Setter Property="Background" Value="Red" />
    </Style>
  </Windows.Resources>
  <StackPanel>
    <local:MyControl FirstButtonStyle="{StaticResource GreenButton}"
                     SecondButtonStyle="{StaticResource RedButton}" />
  </StackPanel>
</Window>

Alternatively you could have the 2 buttons share the same Style by exposing a single property in your custom control which you bind to the Style property of both internal controls.

UPDATE

You don't have to define the FirstButtonStyle and SecondButtonStyle properties as dependency properties. The important thing is that the internal bindings to the buttons' Style properties are updated whenever their value changes. You can accomplish this by implementing the INotifyPropertyChanged interface in your user control and raise the OnPropertyChanged event in the property setters.

You could also assign a "default style" to the 2 properties in the user control's constructor. Here is an example:

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace MyNamespace
{
  [StyleTypedProperty(
  Property = "FirstButtonStyle",
  StyleTargetType = typeof(Button))]
  [StyleTypedProperty(
  Property = "SecondButtonStyle",
  StyleTargetType = typeof(Button))]
  public partial class MyControl : UserControl, INotifyPropertyChanged
  {
    private Style firstButtonStyle;
    private Style secondButtonStyle;

    public MyControl()
    {
      Style defaultStyle = new Style();
      // assign property setters to customize the style

      this.FirstButtonStyle = defaultStyle;
      this.SecondButtonStyle = defaultStyle; 
    }

    public Style FirstButtonStyle
    {          
      get { return firstButtonStyle; }
      set
      {
         firstButtonStyle = value;
         OnPropertyChanged("FirstButtonStyle");
      }
    }

    public Style SecondButtonStyle
    {          
      get { return secondButtonStyle; }
      set
      {
         secondButtonStyle = value;
         OnPropertyChanged("SecondButtonStyle");
      }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}
Enrico Campidoglio
Ciao Enrico, thank you for the answer. Your solution for sure will work well but I would like to know if it is possible to reach my target even without defining the styles as dependecy properties. I would like to define two styles as static resources (x:Key=...) in XAML and extend in the application
marco.ragogna
I updated the answer according to your feedback :)
Enrico Campidoglio
Thank you Enrico. Do you know if this is possible overrides the styles even without defining any dedicated property in the custom control. I mean only creating two styles in the default xaml as static resources?
marco.ragogna