WPF Binding Border Color in Custom Button

RedEyedMonster

I have an application where a number of custom buttons are dynamically generated within a WrapPanel. All works fine and I am able to assign border thickness, ImageSource, Content etc. as I generate the buttons in code. The customer now has a requirement to allow them to choose border colours for individual buttons and try as I might I cannot figure out the correct binding scenario. I'm on a steep WPF learning curve here so it may be that my initial design is somewhat off kilter.

In my Generic.XAML I have the button specified thus:

<Style TargetType="{x:Type local:LauncherButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:LauncherButton}">
                        <Border Name="LauncherButtonBorder" BorderThickness="{TemplateBinding BThickness}"
                                CornerRadius="10" Background="White" >

                            <Border.Style>
                                <Style TargetType="{x:Type Border}">
                                    <Setter Property="BorderBrush" Value="SteelBlue" />

                                    <Style.Triggers>
                                        <Trigger Property="IsMouseOver" Value="True">
                                            <Setter Property="BorderBrush" Value="PaleGoldenrod" />
                                        </Trigger>
                                    </Style.Triggers>

                                </Style>
                            </Border.Style>
                            <DockPanel LastChildFill="True" Background="White" Margin="3">
                                <TextBlock Text="{TemplateBinding Content}" HorizontalAlignment="Center"
                                           Foreground="{DynamicResource TaskButtonTextBrush}" FontWeight="Bold"
                                           Margin="5,0,0,0" VerticalAlignment="Center" FontSize="10"
                                           Background="Transparent" DockPanel.Dock="Bottom" TextWrapping="Wrap" />
                                <Image Source="{TemplateBinding ImageSource}" Stretch="Uniform" />
                            </DockPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

I want to dynamically change in c# the border colours that are currently set to static SteelBlue and PaleGoldenrod.

The button class is defined thus:

public class LauncherButton : ButtonBase
    {
        static LauncherButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(LauncherButton), new FrameworkPropertyMetadata(typeof(LauncherButton)));
        }

        public ImageSource ImageSource
        {
            get { return (ImageSource)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }

        }

        public Thickness BThickness
        {
            get { return (Thickness) GetValue(BThicknessProperty); }
            set { SetValue(BThicknessProperty,value);}
        }



                public static readonly DependencyProperty ImageSourceProperty =
            DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(LauncherButton), new UIPropertyMetadata(null));

        public static readonly DependencyProperty BThicknessProperty =
             DependencyProperty.Register("BThickness", typeof(Thickness), typeof(LauncherButton), new UIPropertyMetadata(null));


    }

and I'm binding some of the properties to an instance of the following class:

public class CustomButton:INotifyPropertyChanged
{
    private string _type;
    private string _buttonId;
    private string _name;
    private string _image;
    private string _link;
    private string _parent;
    private List<CustomButton> _children;
    private bool _isExpanded;
    private bool _isSelected;


    public string ButtonId
    {
        get { return _buttonId; }
        set
        {
            if (value == _buttonId) return;
            _buttonId = value;
            OnPropertyChanged("ButtonId");
        }
    }

    public string Type
    {
        get { return _type; }
        set
        {
            if (value == _type) return;
            _type = value;
            OnPropertyChanged("Type");
        }
    }

    public string Name
    {
        get { return _name; }
        set
        {
            if (value == _name) return;
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    public string Image
    {
        get { return _image; }
        set
        {
            if (value == _image) return;
            _image = value;
            OnPropertyChanged("Image");
        }
    }

    public string Link
    {
        get { return _link; }
        set
        {
            if (value == _link) return;
            _link = value;
            OnPropertyChanged("Link");
        }
    }

    public string Parent
    {
        get { return _parent; }
        set
        {
            if (value == _parent) return;
            _parent = value;
            OnPropertyChanged("Parent");
        }
    }

    public List<CustomButton> Children
    {
        get { return _children; }
        set
        {
            if (Equals(value, _children)) return;
            _children = value;
            OnPropertyChanged("Children");
        }
    }

    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (value.Equals(_isExpanded)) return;
            _isExpanded = value;
            OnPropertyChanged("IsExpanded");
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value.Equals(_isSelected)) return;
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
Viv

Are you trying to make the two brushes used for Border.BorderBrush dynamic?

If so you can address it in a few ways.

  • Add two dependency properties to LauncherButton for say NormalBorderBrush and MouseOverBorderBrush and then set it as you wish when you use the Button. Now to get the Border to use this, within it's Style where you set SteelBlue or PaleGoldenRod, apply a RelativeSource FindAncestor binding with AncestorType as local:LauncherButton and point it to the corresponding Brush(NormalBorderBrush or MouseOverBorderBrush)

Example:

public class LauncherButton : ButtonBase {
  ...

  public static readonly DependencyProperty NormalBorderBrushProperty =
    DependencyProperty.Register("NormalBorderBrush", typeof(Brush), typeof(LauncherButton),
      new UIPropertyMetadata(Brushes.Blue));

  public static readonly DependencyProperty MouseOverBorderBrushProperty =
    DependencyProperty.Register("MouseOverBorderBrush", typeof(Brush), typeof(LauncherButton),
      new UIPropertyMetadata(Brushes.Red));

  public Brush NormalBorderBrush
  {
    get { return (Brush)GetValue(NormalBorderBrushProperty); }
    set { SetValue(NormalBorderBrushProperty, value); }
  }

  public Brush MouseOverBorderBrush
  {
    get { return (Brush)GetValue(MouseOverBorderBrushProperty); }
    set { SetValue(MouseOverBorderBrushProperty, value); }
  }
}

in xaml:

<Border.Style>
  <Style TargetType="{x:Type Border}">
    <Setter Property="BorderBrush"
            Value="{Binding RelativeSource={RelativeSource FindAncestor,
                                                            AncestorType={x:Type local:LauncherButton}},
                            Path=NormalBorderBrush}" />
    <Style.Triggers>
      <Trigger Property="IsMouseOver"
                Value="True">
        <Setter Property="BorderBrush"
                Value="{Binding RelativeSource={RelativeSource FindAncestor,
                                                                AncestorType={x:Type local:LauncherButton}},
                                Path=MouseOverBorderBrush}" />
      </Trigger>
    </Style.Triggers>
  </Style>
</Border.Style>

and usage:

<local:LauncherButton BThickness="5"
                      Content="Hellooooo"
                      MouseOverBorderBrush="Green"
                      NormalBorderBrush="Aqua" />

Sample Download - This does not contain the converter for Brush usage, that should be easy enough to implement.

  • OR You could have two brushes defined as dynamic resources and override their color's from your code when you need to.
  • OR You can use the Button's BorderBrush property which it already has and apply this to the Border with a TemplateBinding BorderBrush. Now this would mean you need to switch the BorderBrush accordingly when your IsMouseOver state change occurs.
  • OR you could even go to extents of retrieving the button's Style and getting a reference to the Border element by finding it via it's Name and then tweaking it at run-time.

Personally I'd opt for option 1. Finally use a converter or likewise in the Binding to make it MVVM friendly.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related