Search code examples
c#wpf

INotifyPropertyChanged is not working in WPF


I need to enable and disable a datagrid through button click. This is how I do it:

MainWindow

public bool IsReadOnly = true;
private MainWindowEngine mwe;

public MainWindow()
{
  InitializeComponent();
  InitialSettings();
  DataContext = mwe;
}

private void InitialSettings()
        {
            _mwe = new MainWindowEngine();
            IsReadOnly = bool.Parse(_mwe.IsReadOnly);
            DataGridCommands.IsReadOnly = IsReadOnly;
            DataGridReaders.IsReadOnly = IsReadOnly;
        }

        private void EnableEdit(object sender, RoutedEventArgs e)
        {
            IsReadOnly = !IsReadOnly;
            _mwe.IsReadOnly = IsReadOnly.ToString();
        }

xaml

<Button
                            Name="ButtonEdit"
                            Grid.Column="1"
                            Content="Edit" 
                            VerticalAlignment="Center" 
                            HorizontalAlignment="Center"
                            Margin="5 0 0 0"
                            Width="75" Click="EnableEdit"
                        />


class MainWindowEngine : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private string _isReadOnly = "true";

        public string IsReadOnly
        {
            get => _isReadOnly;
            set
            {
                if (_isReadOnly != value)
                {
                    _isReadOnly = value;
                    OnIsReadOnlyChanged(_isReadOnly);
                }
            }
        }

        protected void OnIsReadOnlyChanged(string value)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(value));
        }
    }

Through debugger, it is hitting the breakpoints but it doesn't make my datagrid isReadOnly property to false or true.


Solution

  • Change it like shown below. Pass the name of the property instead of its value to the method that fires the PropertyChanged event. Also change the name of the method to something that reflects its general purpose, i.e. to notify about the change of any property, not just IsReadOnly.

    public string IsReadOnly
    {
        get => _isReadOnly;
        set
        {
            if (_isReadOnly != value)
            {
                _isReadOnly = value;
                OnPropertyChanged(nameof(IsReadOnly));
            }
        }
    }
    
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    

    See the documentation - https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged?view=net-5.0

    You need to notify the name of the property that changed, not the value directly.

    Edit - If you do not want to write out your property names always, you can invoke the PropertyChanged event using the CallerMemberName as below -

    public string IsReadOnly
    {
        get => _isReadOnly;
        set
        {
            if (_isReadOnly != value)
            {
                _isReadOnly = value;
                OnPropertyChanged(); // no longer need to pass the property name
            }
        }
    }
    
    protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }