1
votes

I have a button in a UserControl. The code I supply here is simple, just to illustrate you the situation. That's why I included a second button to allow significative user interaction. The UserControl xaml code is as follows:

<UserControl x:Class="WpfControlLibrary1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfControlLibrary1"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" x:Name="MyUserControl">
    <Grid>       
        <Button Name="btSelectColor"  ToolTip="Select color" Width="23" Height="23"  BorderBrush="#FF070707" Background="{Binding Mode=OneWay, ElementName=MyUserControl, Path=CurrentColorBrush}"></Button>
        <Button Name="btChangeColor"  ToolTip="For change color for testing" Width="120" Height="23" Margin="90,166,90,110" Click="btChangeColor_Click">Test color changing</Button>
    </Grid>
</UserControl>

The ElementName property value is MyUserControl, which is the same value of the UserControl x:Name attribute. The Path value is CurrentColorBrush which is the wrap of a dependency property defined in the code behind as follows:

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

namespace WpfControlLibrary1
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {

            InitializeComponent();
            CurrentColorBrush = new SolidColorBrush(Color.FromArgb(1, 150, 250, 150));

        }

        public static readonly DependencyProperty currentColorBrushProperty = DependencyProperty.Register("CurrentColorBrush", typeof(SolidColorBrush), typeof(UserControl1));

        public SolidColorBrush CurrentColorBrush
        {
            get
            {
                return (SolidColorBrush)GetValue(currentColorBrushProperty);
            }
            set
            {
                SetValue(currentColorBrushProperty, value);
            }
        }
        private void btChangeColor_Click(object sender, RoutedEventArgs e)
        {
            CurrentColorBrush = new SolidColorBrush(Color.FromArgb(1, System.Convert.ToByte(CurrentColorBrush.Color.R - 20), 15, 15));
        }

    }
}

I set a default value to this property in the constructor of the UserControl using the following statement:

CurrentColorBrush = new SolidColorBrush(Color.FromArgb(1, 150, 250, 150));

The problem is that, when the window containing the Usercontrol is shown, the button background is not of the default color defined in the UserControl’s constructor. Even if the second button is clicked, the background of the first button remains the same. Weirder, if the Visual Tree is inspected in runtime you can see that the expected values are in place but you never see the change graphically . The UserControl is in a separate WPF User Control Library project. I'm using Visual Studio 2017.

EDITED*****************************

The solution proposed by Aybe gave me a clue. The code works and is similar to mine. So, I started to look for differences and I realized that the initial value for CurrentBrush in my code is a SolidColorBrush defined from a Color. This Color was defined from RGBA values picked under no special criteria. The fact is that, when I use (as Aybe did) standard values of brushes like Brushes.DarkCyan everything works well. Maybe I was providing RGB values that create a color which is not valid for Background property. I don't know if there are any limitations of this kind but the behavior of my code could point to something like this. I googled it but I couldn't find anything about this matter. Do you have any idea?

2
You should paste more code. - aybe
Thanks Aybe... More code pasted. - user2634979

2 Answers

0
votes

Here is the smallest possible example that works, for every case you mentioned:

Window:

<Window
    x:Class="WpfApp1.MainWindow"
    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:local="clr-namespace:WpfApp1"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <StackPanel>
        <local:UserControl1 x:Name="uc1" />
        <Button
            Background="{Binding ElementName=uc1, Path=CurrentBrush}"
            Click="Button_Click"
            Content="Button1" />
    </StackPanel>
</Window>

Window:

using System.Windows;
using System.Windows.Media;

namespace WpfApp1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // this will work but beware that button focus hides it
            // move the mouse away from button to see that it worked
            uc1.CurrentBrush = Brushes.PaleVioletRed;
        }
    }
}

Control:

<UserControl
    x:Class="WpfApp1.UserControl1"
    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"
    mc:Ignorable="d">
    <Grid>
        <TextBlock Text="Hello, world !" />
    </Grid>
</UserControl>

Control:

using System.Windows;
using System.Windows.Media;

namespace WpfApp1
{
    public partial class UserControl1
    {
        // the default value is specified in the metadata, below
        // I changed it from default(Brush) to Aqua
        public static readonly DependencyProperty CurrentBrushProperty = DependencyProperty.Register(
            "CurrentBrush", typeof(Brush), typeof(UserControl1), new PropertyMetadata(Brushes.Aqua));

        public UserControl1()
        {
            InitializeComponent();

            // this will override the default value above
            CurrentBrush = Brushes.DarkCyan;
        }

        public Brush CurrentBrush
        {
            get => (Brush) GetValue(CurrentBrushProperty);
            set => SetValue(CurrentBrushProperty, value);
        }
    }
}

Note: beware of the XAML designer of Visual Studio, sometimes changes are not reflected, i.e. prefer the XAML designer of Expression Blend

0
votes

Try to use a specific overload of your dependency property creation that allow you to specify a default value

here is an article about the dp's default value