views:

117

answers:

3

In the following example, the Message property binds correctly but the FirstName, LastName and Age properties of the Customer object are blank. Why is that?

XAML:

<Window x:Class="TestBinding9922.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>

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

        <Grid DataContext="{Binding Customer}" >
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Label Grid.Column="0" Grid.Row="0" Content="First Name:" />
            <Label Grid.Column="0" Grid.Row="1" Content="Last Name:" />
            <Label Grid.Column="0" Grid.Row="2" Content="Age:" />

            <TextBox Grid.Column="1" Grid.Row="0" Text="{Binding FirstName}" />
            <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding LastName}" />
            <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Age}" />

        </Grid>

    </StackPanel>
</Window>

Code-Behind:

using System.Windows;
using System.ComponentModel;

namespace TestBinding9922
{
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public string Message { get; set; }
        public Customer Customer { get; set; }

        public Window1()
        {
            InitializeComponent();
            DataContext = this;

            Message = "this works";

            Customer customer = new Customer() { FirstName = "Jim", LastName = "Smith", Age = 45 };
        }
    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }
}

Addendum:

Even when I use INotifyPropertyChanged, the textboxes are still blank:

using System.Windows;
using System.ComponentModel;

namespace TestBinding9922
{
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        #region ViewModelProperty: Message
        private string _message;
        public string Message
        {
            get
            {
                return _message;
            }

            set
            {
                _message = value;
                OnPropertyChanged("Message");
            }
        }
        #endregion

        #region ViewModelProperty: Customer
        private Customer _customer;
        public Customer Customer
        {
            get
            {
                return _customer;
            }

            set
            {
                _customer = value;
                OnPropertyChanged("Customer");
            }
        }
        #endregion

        public Window1()
        {
            InitializeComponent();
            DataContext = this;

            Message = "this works";

            Customer customer = new Customer() { FirstName = "Jim", LastName = "Smith", Age = 45 };
        }

        #region INotifiedProperty Block
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }

}
+2  A: 

Your Customer class needs to implement INotifyPropertyChanged and subsequently the properties that are being changed need to notify when they get changed.

You can find an example of this here, among other places.

Also, you're not instantiating your Customer property, you're creating a local variable; it should be:

Customer = new Customer() 
    { FirstName = "Jim", LastName = "Smith", Age = 45 };
Joseph
I cannot believe that the author of the blog entry you linked to considers his solution simple and elegant. If WPF truly simplified development I would be a fan, but after using it quite a bit, I feel it just pushes the pain to new and undocumented areas.
PeterAllenWebb
thanks, I oversaw that I was defining a local variable, it works now, even without the INotifyPropertyChanged
Edward Tanguay
@Peter Yeah databinding is not a pretty thing right now. I'm not even sure you need it all of the time. I'm pretty sure you'll need to implement an INotifyPropertyChanged scheme if you're doing two way binding.
Joseph
+2  A: 

It looks like you're assigning the new Customer instance to a local variable "customer" instead of to your Window's property.

Drew Marsh
A: 

You could remove the setting of the DataContext for the grid in the XAML, and then bind the textboxes to Customer.FirstName, etc.

Or, you could remove the setting of the DataContext for the grid in the XAML, as before, but give the grid a name, and then set its DataContext in the code-behind, like you did for the window.

Jeff Mather