1

I am trying to change to color of button when clicked. It is taking the initial color assigned but not updating when clicked. I attaching my code, let me know where I am going wrong. I tried to implement the code provided in the following post

enter link description here

MainWindow.xaml snippet

<Window.Resources>
    <viewModels:MainWindowViewModel x:Key="MainViewModel"/>
</Window.Resources>

<Border Padding="20">
    <StackPanel DataContext="{Binding Source={StaticResource MainViewModel}}">
        <Button Content="Button1" Margin="10 10 10 10" Command="{Binding ClickCommand, Mode=OneWay}" Background="{Binding BackgroundColorBtn1}"/>
        <Button Content="Button2 " Margin="10 10 10 10"></Button>
    </StackPanel>
</Border>

</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }

        private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
        {
            var desktopWorkingArea = System.Windows.SystemParameters.WorkArea;
            this.Left = desktopWorkingArea.Right - this.Width;
            this.Top = desktopWorkingArea.Bottom - this.Height;
        }
    }

MainWindowViewModel.cs

namespace DockedPanel.ViewModels
{
    public class MainWindowViewModel:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public MainWindowViewModel()
        {
            _canExecute = true;
        }
        private ICommand _clickCommand;
        public ICommand ClickCommand
        {
            get
            {
                return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute));
            }
        }
        private bool _canExecute;
        public void MyAction()
        {
            _backgroundColorBtn1 = Colors.Blue;
        }

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private Color _backgroundColorBtn1 =  Colors.White;
        public Color BackgroundColorBtn1
        {
            get { return _backgroundColorBtn1; }
            set
            {
                if (value == _backgroundColorBtn1)
                    return;

                _backgroundColorBtn1 = value;

                OnPropertyChanged(nameof(BackgroundColorBtn1));
            }
        }
    }
}

and finally CommandHandler

namespace DockedPanel.ViewModels.Command
{
    public class CommandHandler : ICommand
    {
        private Action _action;
        private bool _canExecute;
        public CommandHandler(Action action, bool canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            _action();
        }
    }
}
Manoj Pathak
  • 209
  • 1
  • 5
  • 15

1 Answers1

2

You need to call OnPropertyChanged on the BackgroundColorBtn1 property since you are changing the private backing variable, and the View needs to be notified.

You can modify your MyAction method as following

 public void MyAction()
 {
      _backgroundColorBtn1 = Colors.Blue;
      OnPropertyChanged(nameof(BackgroundColorBtn1));
 }

Alternatively, you could set the Property directly instead of backing field, which would invoke the OnPropertyChanged call itself.

 public void MyAction()
 {
      BackgroundColorBtn1 = Colors.Blue;
 }

You would also need to use a Color To Brush Converter. The background property of button accepts Brush, not color. The convertor would allow you to convert the chosen Color to Brush.

You can define the Converter as following

public class ColorToSolidColorBrushValueConverter : IValueConverter 
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return null;

        if (value is Color)
            return new SolidColorBrush((Color)value);

        throw new InvalidOperationException("Unsupported type [" + value.GetType().Name + "], ColorToSolidColorBrushValueConverter.Convert()");
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
        throw new NotImplementedException();
    }
}

And then, you can use it as

Background="{Binding BackgroundColorBtn1, Converter={StaticResource colorToSolidColorBrushConverter}}"

Please ensure you have added following to your Resource section before using it

<Window.Resources>
<ResourceDictionary>
        <myNameSpace:ColorToSolidColorBrushValueConverter  x:Key="colorToSolidColorBrushConverter"/>
</ResourceDictionary>
</Window.Resources>
Anu Viswan
  • 17,797
  • 2
  • 22
  • 51
  • It is probably better to set the property instead of the backing field. The setter of the property already has all the necessary logic to raise property change notifications... –  Feb 20 '19 at 00:53
  • @elgonzo yes. will mention the same in answer. Had answered about Private field since he had used it and wanted to point out what was causing the issue. – Anu Viswan Feb 20 '19 at 00:54
  • Thank you @Anu Viswan, I tried both the ways but its still not changing to blue when clicked. – Manoj Pathak Feb 20 '19 at 01:04
  • @ManojPathak I have updated my answer., Could you please check., You are missing a Color to brush converter as well – Anu Viswan Feb 20 '19 at 01:18