views:

304

answers:

1

For some reason I'm really struggling with this. I'm new to wpf and I can't seem to find the information I need to understand this simple problem.

I am trying to bind a textbox to a string, the output of the programs activity. I created a property for the string, but when the property changes, the textbox does not. I had this problem with a listview, but created a dispatcher which refreshes the listview.

I must be missing some major point, because I thought one benefit of using wpf was not having to update controls manually. I hope someone can send me in the right direction.

in windowMain.xaml.cs

private string debugLogText = "initial value";

public String debugLog {
    get { return debugLogText; }
    set { debugLogText = value; }
}

in windowMain.xaml

x:Name="wndowMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}"

<TextBox Name="txtDebug" Text="{Binding ElementName=wndowMain, Path=debugLog}" />
+4  A: 

Implement INotifyPropertyChanged on your class. If you have many classes that need this interface, I often find it helpful to use a base class like the following.

public abstract class ObservableObject : INotifyPropertyChanged
{

    protected ObservableObject( )
    {
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged( PropertyChangedEventArgs e )
    {
        var handler = PropertyChanged;
        if ( handler != null ) {
            handler( this, e );
        }
    }

    protected void OnPropertyChanged( string propertyName )
    {
        OnPropertyChanged( new PropertyChangedEventArgs( propertyName ) );
    }

}

Then you just have to make sure you raise the PropertyChanged event whenever a property value changes. For example:

public class Person : ObservableObject {

    private string name;

    public string Name {
        get {
              return name;
        }
        set {
              if ( value != name ) {
                  name = value;
                  OnPropertyChanged("Name");
              }
        }
    }

}
Josh Einstein
+1 for the ObservableObject class!
Peter Gfader
Why this extra work with the var handler = PropertyChanged;? Thread safety?
Peter Gfader
Yeah it's just a habit I picked up. Even though it's pretty unlikely that you'll be raising/subscribing to this from different threads there's not much harm in it and it's become something of a reflex. Others have shown you can eliminate the check by initializing the event like:public event PropertyChangedEventHandler PropertyChanged = delegate{};But it's not only slow, it feels hacked. :)
Josh Einstein
Re the {} - indeed; the problem then is that you pay for a delegate-invoke on every property change, even if nobody is looking...
Marc Gravell
For info - a (possibly) useful addition to the above: protected void SetField<T>(ref T field, T value, string propertyName) {if(!EqualityComparer<T>.Default.Equals(field,value)) {field = value;OnPropertyChanged(propertyName);}} - then you can use (in the set) SetField(ref name, value, "Name"); etc,
Marc Gravell
Nice! That's going in the base class. :)
Josh Einstein
This is nice, and it worked. I was able to do the binding in code and everything works as it should. After some searching, I see you improved upon the example from http://blogs.msdn.com/wpfsdk/archive/2006/10/19/wpf-basic-data-binding-faq.aspx So many hours in the wrong direction, so Thank You.
SixOThree