none
Binding via ViewModel not working

    Question

  • Hi all

    I have a small proof of concept app trying to get a WCF RESTful service talking to MVVM without success so far.

    In the XAML view I have a simple grid like this:

    <sdk:DataGrid x:Name="dgCars" Margin="20" AutoGenerateColumns="True" ItemsSource="{Binding FastCars, Mode=TwoWay}" />

    I set my data context in the code behind of the view like this:

    carViewModel vmCars = new carViewModel(); 
    vmCars.GetCarsData();
    this.DataContext = vmCars;

    My ViewModel:

      public class carViewModel : INotifyPropertyChanged
      {
        private XNamespace dataNameSpace = "http://schemas.datacontract.org/2004/07/SPOC2.Web.Entities";
        public event PropertyChangedEventHandler PropertyChanged;
    
        private ObservableCollection<car> _fastCars;
        public ObservableCollection<car> FastCars
        {
          get { return _fastCars; }
          set {_fastCars = (ObservableCollection<car>)value; }
        }
    
        public void GetCarsData()
        {
          string baseUrl = "http://localhost:50434/REST/CarService.svc/";
          Uri serviceUri = new Uri(baseUrl + "cars");
    
          WebClient webClient = new WebClient();
          webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
          webClient.DownloadStringAsync(serviceUri);
        }
    
        void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
          XDocument doc = XDocument.Parse(e.Result);
    
          var carsFromXml = from results in doc.Descendants(dataNameSpace + "Car")
                     select new car
                     {
                       CarMake = results.Element(dataNameSpace + "CarMake").Value,
                       CarModel = results.Element(dataNameSpace + "CarModel").Value
                     };
    
          ObservableCollection<car> c =  new ObservableCollection<car>();
          foreach (car carNode in carsFromXml)
          {
            c.Add(carNode);
          }
    
          FastCars = c;
        }

    When stepping through the code I can see that my service call is working and the public property FastCars in the viewModel is being populated, but it is not notifying the UI and no data is displayed.

    If I call another method (GetStaticData) with static data instead, it works just fine and the grid is populated with data. My static method looks like this:

    public void GetCarsDataStatic()
        {
          // This will typically be your web service call
          ObservableCollection<car> c = new ObservableCollection<car>();
          car car1 = new car();
          car1.CarMake = "VW";
          car1.CarModel = "Beetle";
          c.Add(car1);
          car car2 = new car();
          car2.CarMake = "Ford";
          car2.CarModel = "Fairlane";
          c.Add(car2);
          car car3 = new car();
          car3.CarMake = "Dodge";
          car3.CarModel = "Viper";
          c.Add(car3);
    
          FastCars = c;
        }

    Both populate the same public property FastCars which is a observableCollection. The GetData method that calls the service and populates FastCars via the webClient_DownloadStringCompleted event, does nto show any data.

    If I move my GetData call and the webClient_DownloadStringCompleted to the code-behind of the XAML, then it works, but then it won't be MVVM anymore.

    Please help.

    Thanks

    Neville

    Sunday, April 22, 2012 5:15 PM

Answers

  • Hi Neville,

    I find that that you implement INotifyPropertyChanged interface in ViewModel, but i didn't see how you implement the method of PropertyChanged. This may cause that the data change cannot reflect in UI automatically at runtime.

        private ObservableCollection<car> _fastCars;
        public ObservableCollection<car> FastCars
        {
          get { return _fastCars; }
          set {

                 _fastCars = (ObservableCollection<car>)value;

                NotifyPropertyChanged("FastCars");

          }
        }
       

            public event PropertyChangedEventHandler PropertyChanged;

            public void NotifyPropertyChanged(string MemberName)
            {
                if (PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs(MemberName));
                }
            }

     

    Best Regards,

    Tuesday, April 24, 2012 2:44 AM

All replies

  • Hi Neville,

    I find that that you implement INotifyPropertyChanged interface in ViewModel, but i didn't see how you implement the method of PropertyChanged. This may cause that the data change cannot reflect in UI automatically at runtime.

        private ObservableCollection<car> _fastCars;
        public ObservableCollection<car> FastCars
        {
          get { return _fastCars; }
          set {

                 _fastCars = (ObservableCollection<car>)value;

                NotifyPropertyChanged("FastCars");

          }
        }
       

            public event PropertyChangedEventHandler PropertyChanged;

            public void NotifyPropertyChanged(string MemberName)
            {
                if (PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs(MemberName));
                }
            }

     

    Best Regards,

    Tuesday, April 24, 2012 2:44 AM
  • Thank you Shi Ding! This is exactly what I was missing and couldn't figure it out because I'm still learning MVVM. For all its complexities I'm not sure I sure the benefit of this pattern. It makes for very complex code with manual event handling and very verbose coding. It is a pitty as Silverlight delivers such a nice, rich user experience, but at such a high development price ... but I degress, sorry.

    How do I display a value returned from my serivice in a simple TextBlock? TextBlock has not ItemSource property to which I can bind a public viewModel property? And since the service call is asyncronous, I can not just write the result to the TextBox's value property in the code behind of my view either. See, something so simple, yet so complicated?

     

    Tuesday, April 24, 2012 4:58 AM
  • Hi elliveN,

    For middle or large scale project, you will feel more benefit from MVVM because it seperate ui code and business code, make the structure of project clearer and easy to understand and maintain. Still MVVM is just a pattern, it is not neccessary to follow this pattern strictly for some special situation MVVM does make the coding far more complicated than just putting logic code in code behind. So you can choose to partially follow this pattern as long as making the project logical clear and easy to understand.

    How do I display a value returned from my serivice in a simple TextBlock? TextBlock has not ItemSource property to which I can bind a public viewModel property?And since the service call is asyncronous, I can not just write the result to the TextBox's value property in the code behind of my view either

    TextBlock has Text property which can be bound to a variable. You don't need to worry much about the value returned from service happens asynchronous, just bind a data field to Text property with two way mode and implemenet INotifyPropertyChange, then whenever data is changed in ViewModel it will reflect on UI automatically. Similar to what you have done with DataGrid's ItemsSource.

     

    Best Regards,

    Tuesday, April 24, 2012 11:30 PM
  • Thanks for  your response Shi. It makes sense but I still feel there is nothing simple or easy to use about MVVM. I've been seperating business logic from UI for years now without the complexitiy of MVVM. The whole INotifyPropertychanged paradigm adds extra complexity to a typical 3 tierd application which I find unnessary.

    I think I need to learn a bit more about how the binding works though, before I completely write this off.

    Thanks

    Neville

    Wednesday, April 25, 2012 4:28 AM