Search code examples
c#wpfdata-bindingtextboxinotifypropertychanged

WPF PropertyChanged event not firing/updating textbox


I'm still relatively new to Data Binding in wpf, but despite plunging through all the articles and posts here and elsewhere about what could be wrong, I still have not found a solution. The code below is the prevalent information parsed out of my larger files.

I have made sure everything else is working, including adding a property to retrieve the protected parameter options to ensure options.FullPath is in fact getting set/changed on the Browse button's Click event. I attempted to subscribe to the PropertyChanged event in the main window with the line test.PropertyChanged += ShowMessage;, ShowMessage being a method that triggers a MessageBox with text in it. I tried multiple variations on the OnPropertyChanged method from hardcoding it within the calling method to what is displayed here. I even tried setting options to a default value of "" just in case it was being weird about that. No luck on anything, and I have no way to acquire C#6 at the moment, so it may very well be that what I have works with the right language updates, but I just can't tell since it doesn't trigger.

Any help or insight would be greatly appreciated!

EDIT: All of the below code is house within the same namespace.

Object Class:

public class EEOptionSet: INotifyPropertyChanged
{
    public EEOptionSet()
    {
    }
        
    public event PropertyChangedEventHandler PropertyChanged;

    private string _fullPath;

    public string FullPath
    {
        get { return _fullPath; }
        set
        {
            if (value != _fullPath)
            {
                _fullPath = value;
                OnPropertyChanged();
            }
        }
    }

    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

}

Main window's code behind:

public partial class window : Window
{
    protected EEOptionSet options = new EEOptionSet();

    private void BrowseFiles(object sender, RoutedEventArgs e)
    {
        options.FullPath = "Test";
    }
}

Textbox and Button instances in the xaml of my main window (extraneous properties like Grid placement, Alignment, etc removed for brevity):

<TextBox x:Name="FullPathText" Text="{Binding (options.FullPath), Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Focusable="False"/>
<uc:ButtonExt x:Name="Browse" Content="..." Click="BrowseFiles"/>

NOTE: I have also tried:

Text="{Binding options.FullPath, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding Path=options.FullPath, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding Path=(_currentOptionSet.FullPath), Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"

As well as without the IsReadOnly and Focusable properties.


Solution

  • You cannot bind to a protected field.

    Set the DataContext of the window to your field:

    public partial class window : Window
    {
        protected OptionSet options = new OptionSet();
    
        public window()
        {
            InitializeComponent();
            DataContext = options;
        }
    
        private void BrowseFiles(object sender, RoutedEventArgs e)
        {
            options.FullPath = "Test";
        }
    }
    

    ...and remove "options" from the binding path(s) in the XAML markup:

    Text="{Binding FullPath, UpdateSourceTrigger=PropertyChanged}"
    

    Alternatively, make options a public property of the window and set the DataContext the the window itself:

    public partial class window : Window
    {
        public OptionSet options { get; private set; }
    
        public window()
        {
            InitializeComponent();
            options =  = new OptionSet();
            DataContext = this;
        }
    
        private void BrowseFiles(object sender, RoutedEventArgs e)
        {
            options.FullPath = "Test";
        }
    }
    

    Then you should keep the binding path as-is:

    Text="{Binding options.FullPath, UpdateSourceTrigger=PropertyChanged}"