views:

544

answers:

2

I have a real simple example that works nicely without a viewmodel as i have a Item class that implements iNotifyPropertyChanged

public class Item : INotifyPropertyChanged
        {
            private string _name;
            private string _desc;
            public string Name
            {
                get
                { return _name; }
                set
                {
                    if (_name == value)
                        return;
                    _name = value;
                    this.OnPropertyChanged(new PropertyChangedEventArgs("Name"));
                }
            }
                       }
            public event PropertyChangedEventHandler PropertyChanged;

            public Item()
            {

            }

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

        }

This works in a simple example where I have the following code behind:

public MainPage()
    {
        InitializeComponent();

         item = new Item() { Name = "john", Description = "this is my name" };
        LayoutRoot.DataContext = item;
    }

and if I have a button that calls a command handler in the code behind I see changes to the simple UI as propertychanged event is being "listened" to as a result of the Twoway binding on my text property. the handler looks like:

private void Button_Click(object sender, RoutedEventArgs e)
    {


        item.Name = "ted";
        item.Description = "adddress";


    }

so of course this changes the UI (I said this is real simple example) Now I introduce a Viewmodel and the changes to the simple model are not reflected as there is no one listening for the propertychanged.

I set the datacontext in the view to the viewmodel , infact this is the only line of code in the view : LayoutRoot.DataContext = new MyViewModel();

Now my Viewmodel looks like:

public class MyViewModel 
    {
        Item item = null;
        public ICommand ChangeCommand { get; private set; }
        public MyViewModel()
        {
            item = new Item() { Name = "john", Description = "jjjj" };
            ChangeCommand = new DelegateCommand<string>(OnChange);


        }
        private void OnChange(string title)
        {
            item.Name = "bill";

        }

Notes: I use the Patterns and practices commanding to fire the event from the XAML to Viewmodel and this works great

My handler again changes the item.name which results in the setter being called and the this.OnPropertyChanged(new PropertyChangedEventArgs("Name")); being called but no one is listening so no changes are made.

I am trying to keep this example real simple and some will say too simple but I just want to know why the binding is not working. I can pull from the view to viewmodel but I need to able to do the reverse. Am wondering what point I am missing.

A: 

You're binding to an instance of MyViewModel which has no publicly exposed properties. Try making and binding to a public MyViewModel.Item property.

David Cuccia
A: 

actually u seem to be on the right track as i noticed the same thing and changed the code to look like:

private Item _item;

            public ICommand ChangeCommand { get; private set; }
            public MyViewModel()
            {
                myitem = new Item() { Name = "john", Description = "jjjj" };
                ChangeCommand = new DelegateCommand<string>(OnChange);
            }
            private void OnChange(string title)
            {
               _item.Name = "bill";
    //           SelectedItem = _item;

            }
            public Item myitem
            {
                get{return _item;}
                set
                {
                    _item = value;
                    RaisePropertyChanged(new PropertyChangedEventArgs("myitem"));
                }
            }

but my fields were still not filled in till i put a grid around my textfields and set the datacontext thru Grid DataContext="{Binding myitem > in the following XAML:

 - <UserControl
   x:Class="BindingStart.MainPage"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:viewmodel="clr-namespace:BindingStart"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

       xmlns:Commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
       mc:Ignorable="d" d:DesignWidth="640"
   d:DesignHeight="480"
            >
       <UserControl.Resources>
           <viewmodel:MyViewModel x:Key="ViewModel" />
       </UserControl.Resources>   <Grid x:Name="LayoutRoot"
   DataContext="{StaticResource
   ViewModel}">
           <StackPanel>
               <Grid  DataContext="{Binding myitem}">
               <Grid.RowDefinitions>
               <RowDefinition Height="22" />
               <RowDefinition Height="22" />
               <RowDefinition Height="22" />
           </Grid.RowDefinitions>
           <Grid.ColumnDefinitions>
               <ColumnDefinition Width="100" />
               <ColumnDefinition Width="300" />
               <ColumnDefinition Width="20" />
           </Grid.ColumnDefinitions>

           <TextBlock Grid.Row="0" Grid.Column="0" 
   Foreground="Black">SupplierName</TextBlock>
          <TextBox x:Name="SName"  Grid.Row="0" Grid.Column="1 " 
   IsReadOnly="True"     Text="{Binding
   Name, Mode=TwoWay}" />

Now i could have set the context in code but i kind of like the XAML solution. Not sure why I needed to do this step but it seems to work

john mcFetridge