3

I've attached some WPF C# binding code - why doesn't this simple example work? (just trying to understanding binding to a custom object). That is when clicking on the button to increase the counter in the model, the label isn't updated.

<Window x:Class="testapp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button  Height="23" HorizontalAlignment="Left" Margin="20,12,0,0" 
                 Name="testButton" VerticalAlignment="Top" Width="126" 
                 Click="testButton_Click" Content="Increase Counter" />
        <Label Content="{Binding Path=TestCounter}" Height="37" 
               HorizontalAlignment="Right" Margin="0,12,122,0" 
               Name="testLabel2" VerticalAlignment="Top" 
               BorderThickness="3" MinWidth="200"  />
    </Grid>
</Window>


namespace testapp1
{
    public partial class MainWindow : Window
    {
        public TestModel _model;

        public MainWindow()
        {
            InitializeComponent();

            InitializeComponent();
            _model = new TestModel();
            _model.TestCounter = 0;
            this.DataContext = _model;
        }

        private void testButton_Click(object sender, RoutedEventArgs e)
        {
            _model.TestCounter = _model.TestCounter + 1;
            Debug.WriteLine("TestCounter = " + _model.TestCounter);
        }
    }

    public class TestModel : DependencyObject
    {
        public int TestCounter { get; set; }
    }

}

thanks

3 Answers 3

4

For this simple example, consider using INotifyPropertyChanged and not DependencyProperties!

UPDATE If you do want to use DPs, use the propdp snippet in VS2010 or Dr WPF's snippets for VS2008?

Sign up to request clarification or add additional context in comments.

Comments

3

TestCounter needs to be a DepenencyProperty

    public int TestCounter
    {
        get { return (int)GetValue(TestCounterProperty); }
        set { SetValue(TestCounterProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TestCounter.  
    //This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TestCounterProperty =
        DependencyProperty.Register
             ("TestCounter", 
              typeof(int), 
              typeof(TestModel), 
              new UIPropertyMetadata(0));

7 Comments

thanks - just trying this now - so you can never really bind directly to a plain old class object then in WPF?
You can if you implement INotifyPropertyChanged
No, not at all - you can bind to any property of any POCO object, as long as you notify the target (e.g. the TextProperty on your Textbox) of any changes. DependenyProperties do this work for you, but you can also implement INotifyPropertyChanged on the TestModel class (as per @rudigrobler suggestion) and manually raise the change event...
@Daniel - added the following to the TestModel class however it still doesn't work? "public static readonly DependencyProperty TestCounterProperty = DependencyProperty.Register("TestCounter", typeof(int), typeof(TestModel), new UIPropertyMetadata(0));"
hang off - I missed the changes to the TestCounter class
|
1

You can implement the INotifyPropertyChanged interface in the System.ComponentModel namespace. I usually implement a Changed method that can take a number of property names and check for the event not being set. I do that because sometimes I have multiple properties that depend on one value and I can call one method from all of my property setters.

For instance if you had a Rectangle class with Width and Height properties and an Area read-only property that returns Width * Height, you could put Changed("Width", "Area"); in the property setter for Width.

public class TestModel : INotifyPropertyChanged
{
    int m_TestCounter;
    public int TestCounter {
        get {
            return m_TestCounter;
        }
        set {
            m_TestCounter = value;
            Changed("TestCounter");
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    void Changed(params string[] propertyNames)
    {
        if (PropertyChanged != null)
        {
            foreach (string propertyName in propertyNames)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

2 Comments

Jason - just trying to understand how this suggestion would apply to the issue I was having? How would you use this concept here?
When your object is bound to a control, the control adds itself as a listener to the PropertyChanged event from the INotifyPropertyChanged interface. When you fire that event in the property setter the controls bound to that property update in the UI. Your code above will automatically update the UI whenever the TestCounter setter is called. You do need to have a variable behind properties and call the Changed method in your setters, but it's easier to me than using DependencyProperty.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.