Search code examples
c#wpfdata-bindinginotifypropertychangedtextblock

WPF C# PropertyChanged always null


I have played around with this for a while and decided to see if someone can help, I have set in the constructor of StatusInfo the DataContext = this and didn't work. When I write a string to ScreenStatusBarText it does call the OnPropertyChanged method but every time the PropertyChanged value is null. I The status block I have at the bottom of the screen. I have a tab section above this stack panel that has many components that use bindings and work.

Screen Code

<StackPanel Margin="0,1047,0,0">
  <Grid Name="StatusBarItemGrid">
  <TextBlock Name="StatusBarText" Text="may the force be with you"   VerticalAlignment="Center" HorizontalAlignment="Stretch" />
  </Grid>
 </StackPanel>

Data Model:

public partial class StatusInfo :  INotifyPropertyChanged
{

    private string screenStatusBarText;

    public StatusInfo()
    {
        BindScreenStatusBarText();
        screenStatusBarText = "Initialized";
    }

    public string ScreenStatusBarText
    {
        get { return screenStatusBarText; }
        set
        {
            screenStatusBarText = value;
            OnPropertyChanged("StatusBarText");
        }
    }

    private void BindScreenStatusBarText()
    {

        Binding b = new Binding();
        b.Source = screenStatusBarText;
        b.Mode = BindingMode.OneWay;
        b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        b.Path = new PropertyPath("StatusBarText");
        MainWindow.mainWindow.StatusBarText.SetBinding(TextBlock.TextProperty, b);

        MainWindow.mainWindow.StatusBarText.DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string propName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(
                this, new PropertyChangedEventArgs(propName));
    } 
}

My main :

public partial class MainWindow : Window
{
    public static StatusInfo status;
    public MainWindow()
    {
        InitializeComponent();
        SourceInitialized += MainWindow_SourceInitialized;
    }

    private void MainWindow_SourceInitialized(object sender, EventArgs e)
    {
        SetUpDisplay();
    }

    private void SetUpDisplay()
    {
            status = new StatusInfo();
    }
}

Solution

  • Set the Binding in XAML instead of code behind:

    <TextBlock Text="{Binding ScreenStatusBarText}" />
    

    And use a view model like

    public class StatusInfo : INotifyPropertyChanged
    {
        private string screenStatusBarText = "Initialized";
    
        public string ScreenStatusBarText
        {
            get { return screenStatusBarText; }
            set
            {
                screenStatusBarText = value;
                OnPropertyChanged(nameof(ScreenStatusBarText));
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this,
                new PropertyChangedEventArgs(propertyName));
        }
    }
    

    with an instance of the view model class assigned to the MainWindow's DataContext:

    private readonly StatusInfo statusInfo = new StatusInfo();
    
    public MainWindow()
    {
        InitializeComponent();
        DataContext = statusInfo;
    }
    

    You may now access the view model class at any time later, e.g. in an event handler of an element of MainWindow:

    statusInfo.ScreenStatusBarText = "Something";