Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. WPF
  4. MVVM: Transfering data from ViewModel to Model, when and how ? [modified]

MVVM: Transfering data from ViewModel to Model, when and how ? [modified]

Scheduled Pinned Locked Moved WPF
wpfarchitecturequestionannouncement
24 Posts 8 Posters 5 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Jean Louis Leroy

    Hello, There's a lot of talk on the net about the View-ViewModel interaction but little about the ViewModel-Model interaction. I have a Report that has (as a composition) a collection of Parameters. So I have a ReportViewModel that has a collection of ParameterViewModels, a ReportView bound to the ReportViewModel, and the ReportView in turn carries an ItemsControl-full of UserControls bound to the ParameterViewModels. The ReportViewModel's constructor gets passed the Report object and passes the Parameter objects in turn to the sub-viewmodels. The Views and ViewModels interact nicely, the ViewModels "load" themselves from the underlying Models. More precisely, they keep a reference to the Model and synthesize whatever information the View needs. Now for what puzzles me: when/how does the data flow back from ViewModel to Model ? When/how does the user's gesturing finally impacts the Model ? I see that there are at least two possibilities... 1/ Live-update the Model whenever the ViewModel changes. Whenever we want to run operations on the updated Report, there's nothing extra to do. 2/ Implement an explicit "Apply" method in both ViewModels - obviosuly ReportViewModel.Apply will call ParameterViewModel.Apply. Whenever we need an up-to-date Report, first call Apply then save it somewhere, or print it, whatever. What's your take on this ? Jean-Louis

    modified on Tuesday, July 19, 2011 7:49 AM

    P Offline
    P Offline
    Pete OHanlon
    wrote on last edited by
    #2

    You're right. Too often the interaction from the VM back to the M is glossed over. The answer really depends on what you're trying to achieve though. If you are saving data from the view back to a database, for instance, you may want to batch all the changes from a particular edit and submit them at once. Alternatively, your backing store may be updated whenever a property passes validation. This is so dependent on your requirements that there are very few hard and fast rules.

    Forgive your enemies - it messes with their heads

    My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

    1 Reply Last reply
    0
    • J Jean Louis Leroy

      Hello, There's a lot of talk on the net about the View-ViewModel interaction but little about the ViewModel-Model interaction. I have a Report that has (as a composition) a collection of Parameters. So I have a ReportViewModel that has a collection of ParameterViewModels, a ReportView bound to the ReportViewModel, and the ReportView in turn carries an ItemsControl-full of UserControls bound to the ParameterViewModels. The ReportViewModel's constructor gets passed the Report object and passes the Parameter objects in turn to the sub-viewmodels. The Views and ViewModels interact nicely, the ViewModels "load" themselves from the underlying Models. More precisely, they keep a reference to the Model and synthesize whatever information the View needs. Now for what puzzles me: when/how does the data flow back from ViewModel to Model ? When/how does the user's gesturing finally impacts the Model ? I see that there are at least two possibilities... 1/ Live-update the Model whenever the ViewModel changes. Whenever we want to run operations on the updated Report, there's nothing extra to do. 2/ Implement an explicit "Apply" method in both ViewModels - obviosuly ReportViewModel.Apply will call ParameterViewModel.Apply. Whenever we need an up-to-date Report, first call Apply then save it somewhere, or print it, whatever. What's your take on this ? Jean-Louis

      modified on Tuesday, July 19, 2011 7:49 AM

      A Offline
      A Offline
      Abhinav S
      wrote on last edited by
      #3

      When you are setting your binding to two-way, you are updating the model. Yes, your view is bound to the viewmodel and not the model, but the view-model, but if your binding is two-way, the model is going to be udpated. Maybe I've understood your question wrong here though.

      Too much of heaven can bring you underground Heaven can always turn around Too much of heaven, our life is all hell bound Heaven, the kill that makes no sound

      J 1 Reply Last reply
      0
      • A Abhinav S

        When you are setting your binding to two-way, you are updating the model. Yes, your view is bound to the viewmodel and not the model, but the view-model, but if your binding is two-way, the model is going to be udpated. Maybe I've understood your question wrong here though.

        Too much of heaven can bring you underground Heaven can always turn around Too much of heaven, our life is all hell bound Heaven, the kill that makes no sound

        J Offline
        J Offline
        Jean Louis Leroy
        wrote on last edited by
        #4

        I don't bind the view directly to model properties, and I don't want to change that. For starters, I don't like it. Moreover, in the general case it is not always possible. The ViewModel may contain properties that have no direct counterpart in the Model. Also my Model objects contain collections. So I would need to use ObservableCollections...but they're pulled from a Hibernate session so I don't even have control over the exact type of the collections.

        S B 2 Replies Last reply
        0
        • J Jean Louis Leroy

          Hello, There's a lot of talk on the net about the View-ViewModel interaction but little about the ViewModel-Model interaction. I have a Report that has (as a composition) a collection of Parameters. So I have a ReportViewModel that has a collection of ParameterViewModels, a ReportView bound to the ReportViewModel, and the ReportView in turn carries an ItemsControl-full of UserControls bound to the ParameterViewModels. The ReportViewModel's constructor gets passed the Report object and passes the Parameter objects in turn to the sub-viewmodels. The Views and ViewModels interact nicely, the ViewModels "load" themselves from the underlying Models. More precisely, they keep a reference to the Model and synthesize whatever information the View needs. Now for what puzzles me: when/how does the data flow back from ViewModel to Model ? When/how does the user's gesturing finally impacts the Model ? I see that there are at least two possibilities... 1/ Live-update the Model whenever the ViewModel changes. Whenever we want to run operations on the updated Report, there's nothing extra to do. 2/ Implement an explicit "Apply" method in both ViewModels - obviosuly ReportViewModel.Apply will call ParameterViewModel.Apply. Whenever we need an up-to-date Report, first call Apply then save it somewhere, or print it, whatever. What's your take on this ? Jean-Louis

          modified on Tuesday, July 19, 2011 7:49 AM

          R Offline
          R Offline
          RobCroll
          wrote on last edited by
          #5

          I guess people are relucent to publish low-brow MVVM examples in fear of getting shot down in flames. The way I do it (using Entity Framwork) is the ViewModel provides a SaveCommand which the View binds to. After all, it should be up to the user to determine if the data is saved. So when the user clicks the Save button or other events occur, the command is fired and a method can handle the logic to persist the changes back to model. In EF it's a one liner myContext.SaveChanges(); In your situation it sounds like you'll need to do a bit more leg work. But the stategy should still work. You need to catch the event in the ViewModel using a command.

          "You get that on the big jobs."

          1 Reply Last reply
          0
          • J Jean Louis Leroy

            I don't bind the view directly to model properties, and I don't want to change that. For starters, I don't like it. Moreover, in the general case it is not always possible. The ViewModel may contain properties that have no direct counterpart in the Model. Also my Model objects contain collections. So I would need to use ObservableCollections...but they're pulled from a Hibernate session so I don't even have control over the exact type of the collections.

            S Offline
            S Offline
            SledgeHammer01
            wrote on last edited by
            #6

            I may have misread your post, but it seems to me like you have a fundamental misunderstanding of the ViewModel and Model portions. Yes, your View should only bind to stuff in the ViewModel only. However, the ViewModel is not creating, copying, storing, loading, saving, etc. the data, that is the models job. The ViewModel is simply a thin *wrapper* around the model and has a reference to it. If your model is implemented correctly, you shouldn't need much (if any) repackaging of the data. Your ViewModel generally just exposes a bunch of RelayCommands that manipulate the model. If you are doing a lot of repacking work in the ViewModel, or are copying around data a lot... as they say on teh internetz: "UR DOIN IT WRONG!" :)

            J 1 Reply Last reply
            0
            • S SledgeHammer01

              I may have misread your post, but it seems to me like you have a fundamental misunderstanding of the ViewModel and Model portions. Yes, your View should only bind to stuff in the ViewModel only. However, the ViewModel is not creating, copying, storing, loading, saving, etc. the data, that is the models job. The ViewModel is simply a thin *wrapper* around the model and has a reference to it. If your model is implemented correctly, you shouldn't need much (if any) repackaging of the data. Your ViewModel generally just exposes a bunch of RelayCommands that manipulate the model. If you are doing a lot of repacking work in the ViewModel, or are copying around data a lot... as they say on teh internetz: "UR DOIN IT WRONG!" :)

              J Offline
              J Offline
              Jean Louis Leroy
              wrote on last edited by
              #7

              Hmm, I don't think I have a "fundamental misunderstanding". In my app the ViewModel does not store or load data by itself - it tells a DAO to do so. As for validation, it asks the Model to do it. Ok, let's imagine that we rewrite Notepad the MVVM way. We have a Document object with a string property - say Content. And a DocumentViewModel that holds a reference to a Document. It has a a string Content property too, which is loaded from the underlying Document. And then a DocumentView with a text box that binds to the DocumentViewModel's Content. I know I could bind to Document.Content directly but I've beaten that horse in my original post already. Am I on the right track here ? Now loading the ViewModel from the Model has been dealt with but what about the data flowing back from Mr/Ms User to the View to the ViewModel to the Model ? My current take is this… ViewModel exposes commands such as NewCommand, OpenCommand, SaveCommand, SaveAsCommand - and then some more like Copy/Cut/Paste Commands. NewCommand.Execute checks whether pending changes exist and possibly offers to save. Then it sets the VM's Document to a "new Document()". The VM updates its Content property and fires an event. SaveCommand.CanExecute returns True if the document has been changed. SaveCommand.Execute copies the text from VM.Content to Document.Content then tells some object to save the document - via an interface so it can be mocked and unit-tested. SaveAsCommand.Execute…hmmm…I guess it sets the VM's Document to a "new Document()" before transferring the VM.Content to Document.Content. But this assumes that the VM has copied all the Document's information. Or maybe the Document is cloneable and we replace the VM.Document with VM.Document.Clone() ? Now in my real app, it's a bit messier because the Document is a composition of other objects that have their VM too.

              S L 2 Replies Last reply
              0
              • J Jean Louis Leroy

                Hmm, I don't think I have a "fundamental misunderstanding". In my app the ViewModel does not store or load data by itself - it tells a DAO to do so. As for validation, it asks the Model to do it. Ok, let's imagine that we rewrite Notepad the MVVM way. We have a Document object with a string property - say Content. And a DocumentViewModel that holds a reference to a Document. It has a a string Content property too, which is loaded from the underlying Document. And then a DocumentView with a text box that binds to the DocumentViewModel's Content. I know I could bind to Document.Content directly but I've beaten that horse in my original post already. Am I on the right track here ? Now loading the ViewModel from the Model has been dealt with but what about the data flowing back from Mr/Ms User to the View to the ViewModel to the Model ? My current take is this… ViewModel exposes commands such as NewCommand, OpenCommand, SaveCommand, SaveAsCommand - and then some more like Copy/Cut/Paste Commands. NewCommand.Execute checks whether pending changes exist and possibly offers to save. Then it sets the VM's Document to a "new Document()". The VM updates its Content property and fires an event. SaveCommand.CanExecute returns True if the document has been changed. SaveCommand.Execute copies the text from VM.Content to Document.Content then tells some object to save the document - via an interface so it can be mocked and unit-tested. SaveAsCommand.Execute…hmmm…I guess it sets the VM's Document to a "new Document()" before transferring the VM.Content to Document.Content. But this assumes that the VM has copied all the Document's information. Or maybe the Document is cloneable and we replace the VM.Document with VM.Document.Clone() ? Now in my real app, it's a bit messier because the Document is a composition of other objects that have their VM too.

                S Offline
                S Offline
                SledgeHammer01
                wrote on last edited by
                #8

                Jean-Louis Leroy wrote: Ok, let's imagine that we rewrite Notepad the MVVM way. We have a Document object with a string property - say Content. And a DocumentViewModel that holds a reference to a Document. It has a a string Content property too, which is loaded from the underlying Document. And then a DocumentView with a text box that binds to the DocumentViewModel's Content. I know I could bind to Document.Content directly but I've beaten that horse in my original post already. Am I on the right track here ? --- No, that is exactly what you do *NOT* do. In your example, you have DocumentViewModel that holds a reference to a Document(Model). Document(Model) has a string Content property (the content of the text file). So far, so good. The next step is where you head off the reservation a bit :). DocumentViewModel should DEFINITELY NOT have its own string Content property. It should simply *wrap* the one from the Document(Model). I.e. DocumentViewModel.cs: public string Content { get { return _document.Content; } set { if (_document.Content != value) { _document.Content = value; OnPropertyChanged("Content"); } } } The reasons for this are two-fold: 1) you don't have to worry about keeping the VM and M in sync, since they are always by design in sync 2) you are not storing the same data in multiple places. Imagine if the text file is 100 bytes... no biggie right? your design uses up 200 bytes of memory. No biggie. Now imagine if the text file is 1MB or 10MB or 100MB... with your design, you are using up 2MB, 20MB or 200MB of memory. Not good. Rule #1 in good software design, ESPECIALLY in WPF & MVVM... is that you should only have one instance of an object in memory at all times. The reason why its more important in WPF is that imagine this scenario: SomeObject (inst 1) ... somebody binds to it ... all good... anytime SomeObject (inst 1) is modified, the UI is updated Now imagine that somebody went and made a COPY of SomeObject and now you have SomeObject (inst 2)... changes made to one will not update the properties in the other and data binding will be broken :).

                J P 2 Replies Last reply
                0
                • J Jean Louis Leroy

                  Hmm, I don't think I have a "fundamental misunderstanding". In my app the ViewModel does not store or load data by itself - it tells a DAO to do so. As for validation, it asks the Model to do it. Ok, let's imagine that we rewrite Notepad the MVVM way. We have a Document object with a string property - say Content. And a DocumentViewModel that holds a reference to a Document. It has a a string Content property too, which is loaded from the underlying Document. And then a DocumentView with a text box that binds to the DocumentViewModel's Content. I know I could bind to Document.Content directly but I've beaten that horse in my original post already. Am I on the right track here ? Now loading the ViewModel from the Model has been dealt with but what about the data flowing back from Mr/Ms User to the View to the ViewModel to the Model ? My current take is this… ViewModel exposes commands such as NewCommand, OpenCommand, SaveCommand, SaveAsCommand - and then some more like Copy/Cut/Paste Commands. NewCommand.Execute checks whether pending changes exist and possibly offers to save. Then it sets the VM's Document to a "new Document()". The VM updates its Content property and fires an event. SaveCommand.CanExecute returns True if the document has been changed. SaveCommand.Execute copies the text from VM.Content to Document.Content then tells some object to save the document - via an interface so it can be mocked and unit-tested. SaveAsCommand.Execute…hmmm…I guess it sets the VM's Document to a "new Document()" before transferring the VM.Content to Document.Content. But this assumes that the VM has copied all the Document's information. Or maybe the Document is cloneable and we replace the VM.Document with VM.Document.Clone() ? Now in my real app, it's a bit messier because the Document is a composition of other objects that have their VM too.

                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #9

                  I don't think you have a misunderstanding either, FWIW. There are different ways of doing things - and no one way is intrinsically 'the right way' I tend to get my Model object, use it to create a ViewData object (which I use inside the ViewModel) and don't persist the Model object. I use a specific user-controlled option to update my repository - which creates a new Model from the ViewData

                  MVVM# - See how I did MVVM my way ___________________________________________ Man, you're a god. - walterhevedeich 26/05/2011 .\\axxx (That's an 'M')

                  1 Reply Last reply
                  0
                  • J Jean Louis Leroy

                    Hello, There's a lot of talk on the net about the View-ViewModel interaction but little about the ViewModel-Model interaction. I have a Report that has (as a composition) a collection of Parameters. So I have a ReportViewModel that has a collection of ParameterViewModels, a ReportView bound to the ReportViewModel, and the ReportView in turn carries an ItemsControl-full of UserControls bound to the ParameterViewModels. The ReportViewModel's constructor gets passed the Report object and passes the Parameter objects in turn to the sub-viewmodels. The Views and ViewModels interact nicely, the ViewModels "load" themselves from the underlying Models. More precisely, they keep a reference to the Model and synthesize whatever information the View needs. Now for what puzzles me: when/how does the data flow back from ViewModel to Model ? When/how does the user's gesturing finally impacts the Model ? I see that there are at least two possibilities... 1/ Live-update the Model whenever the ViewModel changes. Whenever we want to run operations on the updated Report, there's nothing extra to do. 2/ Implement an explicit "Apply" method in both ViewModels - obviosuly ReportViewModel.Apply will call ParameterViewModel.Apply. Whenever we need an up-to-date Report, first call Apply then save it somewhere, or print it, whatever. What's your take on this ? Jean-Louis

                    modified on Tuesday, July 19, 2011 7:49 AM

                    L Offline
                    L Offline
                    Lost User
                    wrote on last edited by
                    #10

                    I take option 2 over option 1 'almost always' I treat my Model object as an object whose job it is to go get the data for the client. Once delivered its job is done, so I don't keep a reference to the Model in my ViewModel (again, 'usually' ) So I rarely Update model objects - as they're going to be persisted back in the DB - I create new objects when required and send them back to be stored. I must confess to not quite understanding your scenario here - how your report and Parameter objects interract - but assuming you are maintaining the report and/or parameter objects, then I would normally have some sort of Apply method as per your option2. if you do it this way, then at least you have the option of using the Apply method as frequently or infrequently as you want to - on a timer, every time a parameter type is changed - whatever. But I don't think there's a 'right' way of doing it - and it depends on your exact requirements. One of the downsides of option 1 is the ability to revert changes quickly... As you're maintaining a reference to the Model and want to cancel changes, you can just re-set your VM from the Model and you're back!

                    MVVM# - See how I did MVVM my way ___________________________________________ Man, you're a god. - walterhevedeich 26/05/2011 .\\axxx (That's an 'M')

                    1 Reply Last reply
                    0
                    • S SledgeHammer01

                      Jean-Louis Leroy wrote: Ok, let's imagine that we rewrite Notepad the MVVM way. We have a Document object with a string property - say Content. And a DocumentViewModel that holds a reference to a Document. It has a a string Content property too, which is loaded from the underlying Document. And then a DocumentView with a text box that binds to the DocumentViewModel's Content. I know I could bind to Document.Content directly but I've beaten that horse in my original post already. Am I on the right track here ? --- No, that is exactly what you do *NOT* do. In your example, you have DocumentViewModel that holds a reference to a Document(Model). Document(Model) has a string Content property (the content of the text file). So far, so good. The next step is where you head off the reservation a bit :). DocumentViewModel should DEFINITELY NOT have its own string Content property. It should simply *wrap* the one from the Document(Model). I.e. DocumentViewModel.cs: public string Content { get { return _document.Content; } set { if (_document.Content != value) { _document.Content = value; OnPropertyChanged("Content"); } } } The reasons for this are two-fold: 1) you don't have to worry about keeping the VM and M in sync, since they are always by design in sync 2) you are not storing the same data in multiple places. Imagine if the text file is 100 bytes... no biggie right? your design uses up 200 bytes of memory. No biggie. Now imagine if the text file is 1MB or 10MB or 100MB... with your design, you are using up 2MB, 20MB or 200MB of memory. Not good. Rule #1 in good software design, ESPECIALLY in WPF & MVVM... is that you should only have one instance of an object in memory at all times. The reason why its more important in WPF is that imagine this scenario: SomeObject (inst 1) ... somebody binds to it ... all good... anytime SomeObject (inst 1) is modified, the UI is updated Now imagine that somebody went and made a COPY of SomeObject and now you have SomeObject (inst 2)... changes made to one will not update the properties in the other and data binding will be broken :).

                      J Offline
                      J Offline
                      Jean Louis Leroy
                      wrote on last edited by
                      #11

                      (quotes no in the same order as in the original text)

                      SledgeHammer01 wrote:

                      DocumentViewModel should DEFINITELY NOT have its own string Content property. It should simply *wrap* the one from the Document(Model).

                      Here I stumble upon a difficulty. Consider a Person that has a birth date stored in a DateTime. Obviously we don't want to present that in the VM. Instead we want to map the double Person.BirthDate to a text input field in the view - or three text boxes for day, month and year, or some Calendar control. So what's the VM between View and Model going to look like ? Does it contain one (or three) string properties ? Hmm, maybe something like this ?

                      public string Day
                      {
                        get { return \_person.BirthDate.Day.ToString(); }
                        set { d = \_person.BirthDate.AddDays(int.Parse(value)).AddDays(-\_person.BirthDate.Day); }
                      }
                      
                      public string Month
                      {
                        get { return \_person.BirthDate.Month.ToString(); }
                        set { d = \_person.BirthDate.AddMonths(int.Parse(value)).AddMonths(-\_person.BirthDate.Month); }
                      }
                      
                      public string Year
                      {
                        get { return \_person.BirthDate.Year.ToString(); }
                        set { d = \_person.BirthDate.AddMonths(int.Parse(value)).AddMonths(-\_person.BirthDate.Year); }
                      }
                      

                      Or maybe a ValueConverter is used somewhere ? I haven't explored that yet...

                      SledgeHammer01 wrote:

                      Rule #1 in good software design, ESPECIALLY in WPF & MVVM... is that you should only have one instance of an object in memory at all times

                      I do see your point with having only one instance of an object in memory at all times...especially since I have implemented object-relational mappers like Perl's Tangram. If I have two views looking at the same Model at the same time, I'd want the changes made via one view to be reflected in the other view. Right ? And binding to the Model's property instead of copying them gives me just that. Or does it ? Back to my Person.BirthDate example, suppose that I have VM1 that exposes the birth date as a single string property (BirthDate) in yyyy/mm/dd format. When the View sets the VM's BirthDate property the Model.BirthDate is updated. Now VM2 uses three string properties: Day, Month and Year. But changing the birth date via VM1 fires a "BirthDate" event that is significant only to the View that displays VM1. The change notifications are sent as changes to th

                      J S 2 Replies Last reply
                      0
                      • J Jean Louis Leroy

                        (quotes no in the same order as in the original text)

                        SledgeHammer01 wrote:

                        DocumentViewModel should DEFINITELY NOT have its own string Content property. It should simply *wrap* the one from the Document(Model).

                        Here I stumble upon a difficulty. Consider a Person that has a birth date stored in a DateTime. Obviously we don't want to present that in the VM. Instead we want to map the double Person.BirthDate to a text input field in the view - or three text boxes for day, month and year, or some Calendar control. So what's the VM between View and Model going to look like ? Does it contain one (or three) string properties ? Hmm, maybe something like this ?

                        public string Day
                        {
                          get { return \_person.BirthDate.Day.ToString(); }
                          set { d = \_person.BirthDate.AddDays(int.Parse(value)).AddDays(-\_person.BirthDate.Day); }
                        }
                        
                        public string Month
                        {
                          get { return \_person.BirthDate.Month.ToString(); }
                          set { d = \_person.BirthDate.AddMonths(int.Parse(value)).AddMonths(-\_person.BirthDate.Month); }
                        }
                        
                        public string Year
                        {
                          get { return \_person.BirthDate.Year.ToString(); }
                          set { d = \_person.BirthDate.AddMonths(int.Parse(value)).AddMonths(-\_person.BirthDate.Year); }
                        }
                        

                        Or maybe a ValueConverter is used somewhere ? I haven't explored that yet...

                        SledgeHammer01 wrote:

                        Rule #1 in good software design, ESPECIALLY in WPF & MVVM... is that you should only have one instance of an object in memory at all times

                        I do see your point with having only one instance of an object in memory at all times...especially since I have implemented object-relational mappers like Perl's Tangram. If I have two views looking at the same Model at the same time, I'd want the changes made via one view to be reflected in the other view. Right ? And binding to the Model's property instead of copying them gives me just that. Or does it ? Back to my Person.BirthDate example, suppose that I have VM1 that exposes the birth date as a single string property (BirthDate) in yyyy/mm/dd format. When the View sets the VM's BirthDate property the Model.BirthDate is updated. Now VM2 uses three string properties: Day, Month and Year. But changing the birth date via VM1 fires a "BirthDate" event that is significant only to the View that displays VM1. The change notifications are sent as changes to th

                        J Offline
                        J Offline
                        Jean Louis Leroy
                        wrote on last edited by
                        #12

                        Jean-Louis Leroy wrote:

                        I want to support the New/Open/Save/SaveAs cycle for Reports [...] But how do I implement SaveAs ? By the time I know the end user wants to make a new object, the old one has already been messed up.

                        Thinking about it, one solution out of this problem is to drop the SaveAs command (posterior to changes) and replace it with a Duplicate command (prior changes). Like in Mac OS X Lion :laugh: Then what would Save mean ? Worse, what would it mean if a user changes the data, then never executes Save ? It seems to me that MVVM may end up curbing the way we design UIs. Another example, it discourages modal dialogs, or at least it makes them difficult to implement. I wonder if it's legitimate for a code pattern to have such impact on the end-user experience. Isn't it the tail that wags the dog ?

                        edit: grammar

                        P 1 Reply Last reply
                        0
                        • S SledgeHammer01

                          Jean-Louis Leroy wrote: Ok, let's imagine that we rewrite Notepad the MVVM way. We have a Document object with a string property - say Content. And a DocumentViewModel that holds a reference to a Document. It has a a string Content property too, which is loaded from the underlying Document. And then a DocumentView with a text box that binds to the DocumentViewModel's Content. I know I could bind to Document.Content directly but I've beaten that horse in my original post already. Am I on the right track here ? --- No, that is exactly what you do *NOT* do. In your example, you have DocumentViewModel that holds a reference to a Document(Model). Document(Model) has a string Content property (the content of the text file). So far, so good. The next step is where you head off the reservation a bit :). DocumentViewModel should DEFINITELY NOT have its own string Content property. It should simply *wrap* the one from the Document(Model). I.e. DocumentViewModel.cs: public string Content { get { return _document.Content; } set { if (_document.Content != value) { _document.Content = value; OnPropertyChanged("Content"); } } } The reasons for this are two-fold: 1) you don't have to worry about keeping the VM and M in sync, since they are always by design in sync 2) you are not storing the same data in multiple places. Imagine if the text file is 100 bytes... no biggie right? your design uses up 200 bytes of memory. No biggie. Now imagine if the text file is 1MB or 10MB or 100MB... with your design, you are using up 2MB, 20MB or 200MB of memory. Not good. Rule #1 in good software design, ESPECIALLY in WPF & MVVM... is that you should only have one instance of an object in memory at all times. The reason why its more important in WPF is that imagine this scenario: SomeObject (inst 1) ... somebody binds to it ... all good... anytime SomeObject (inst 1) is modified, the UI is updated Now imagine that somebody went and made a COPY of SomeObject and now you have SomeObject (inst 2)... changes made to one will not update the properties in the other and data binding will be broken :).

                          P Offline
                          P Offline
                          Pete OHanlon
                          wrote on last edited by
                          #13

                          Errm. Are you 100% sure about this design approach as an absolute? How do you handle validation in this case or support for IEditableObject? The reality is, a hybrid approach will generally be necessary. In the case where you want to simply forward a property on, then your approach is fine, but where you need to validate something before it can be committed, then you should use an intermediary value. Similarly, if changes can be rolled back then you should support an intermediary value. That's the approach to use. Take the case you mentioned - where you have a huge amount of text in a model, the VM would generally do some clever processing so that only a subset of the text was kept bound to the view, virtualized in other words, and the model would be updated with the subset. In this way, the VM simply presents a snapshot of some of the text at that point in time.

                          Forgive your enemies - it messes with their heads

                          My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                          S 1 Reply Last reply
                          0
                          • J Jean Louis Leroy

                            Jean-Louis Leroy wrote:

                            I want to support the New/Open/Save/SaveAs cycle for Reports [...] But how do I implement SaveAs ? By the time I know the end user wants to make a new object, the old one has already been messed up.

                            Thinking about it, one solution out of this problem is to drop the SaveAs command (posterior to changes) and replace it with a Duplicate command (prior changes). Like in Mac OS X Lion :laugh: Then what would Save mean ? Worse, what would it mean if a user changes the data, then never executes Save ? It seems to me that MVVM may end up curbing the way we design UIs. Another example, it discourages modal dialogs, or at least it makes them difficult to implement. I wonder if it's legitimate for a code pattern to have such impact on the end-user experience. Isn't it the tail that wags the dog ?

                            edit: grammar

                            P Offline
                            P Offline
                            Pete OHanlon
                            wrote on last edited by
                            #14

                            Jean-Louis Leroy wrote:

                            it discourages modal dialogs, or at least it makes them difficult to implement.

                            Why do you think it makes modal dialogs difficult to implement? I've never found that to be the case.

                            Forgive your enemies - it messes with their heads

                            My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                            J 1 Reply Last reply
                            0
                            • P Pete OHanlon

                              Jean-Louis Leroy wrote:

                              it discourages modal dialogs, or at least it makes them difficult to implement.

                              Why do you think it makes modal dialogs difficult to implement? I've never found that to be the case.

                              Forgive your enemies - it messes with their heads

                              My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                              J Offline
                              J Offline
                              Jean Louis Leroy
                              wrote on last edited by
                              #15

                              Pete O'Hanlon wrote:

                              Why do you think it makes modal dialogs difficult to implement? I've never found that to be the case.

                              I suppose that many get their first exposure to MVVM via Josh Smith's article. But his sample app doesn't contain any modal dialogs. However, it's still one of the first things you need when implementing a real app. So when you turn to Google and search for "MVVM modal dialog" you get flooded with solutions falling roughly in five families: use a control; use a service; overlay a control on your view and disable its controls; what the heck, a bit of code-behind won't hurt; and finally, don't do modal, it's so nineties. It seems that no consensus has emerged on the issue yet (or I've missed it). Not that I care that much about consensus anyway, but, by design or by accident, it's a difficulty for newbies... What solution do you use ?

                              P S 2 Replies Last reply
                              0
                              • J Jean Louis Leroy

                                Pete O'Hanlon wrote:

                                Why do you think it makes modal dialogs difficult to implement? I've never found that to be the case.

                                I suppose that many get their first exposure to MVVM via Josh Smith's article. But his sample app doesn't contain any modal dialogs. However, it's still one of the first things you need when implementing a real app. So when you turn to Google and search for "MVVM modal dialog" you get flooded with solutions falling roughly in five families: use a control; use a service; overlay a control on your view and disable its controls; what the heck, a bit of code-behind won't hurt; and finally, don't do modal, it's so nineties. It seems that no consensus has emerged on the issue yet (or I've missed it). Not that I care that much about consensus anyway, but, by design or by accident, it's a difficulty for newbies... What solution do you use ?

                                P Offline
                                P Offline
                                Pete OHanlon
                                wrote on last edited by
                                #16

                                Over time, I've really settled into using one of two methods (primarily because I contributed to the solutions on them). I originally used the features of Onyx[^] to do the dialogs, but I then moved to using MefedMVVM[^]. I use a modal dialog service that I grab a hold of in my particular VM, and use that to instantiate the dialog. The trick is to use an interface to represent what you want from the dialog, and inject a concrete implementation of this at runtime. It's all very testable, and easy to support.

                                Forgive your enemies - it messes with their heads

                                My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                                1 Reply Last reply
                                0
                                • J Jean Louis Leroy

                                  (quotes no in the same order as in the original text)

                                  SledgeHammer01 wrote:

                                  DocumentViewModel should DEFINITELY NOT have its own string Content property. It should simply *wrap* the one from the Document(Model).

                                  Here I stumble upon a difficulty. Consider a Person that has a birth date stored in a DateTime. Obviously we don't want to present that in the VM. Instead we want to map the double Person.BirthDate to a text input field in the view - or three text boxes for day, month and year, or some Calendar control. So what's the VM between View and Model going to look like ? Does it contain one (or three) string properties ? Hmm, maybe something like this ?

                                  public string Day
                                  {
                                    get { return \_person.BirthDate.Day.ToString(); }
                                    set { d = \_person.BirthDate.AddDays(int.Parse(value)).AddDays(-\_person.BirthDate.Day); }
                                  }
                                  
                                  public string Month
                                  {
                                    get { return \_person.BirthDate.Month.ToString(); }
                                    set { d = \_person.BirthDate.AddMonths(int.Parse(value)).AddMonths(-\_person.BirthDate.Month); }
                                  }
                                  
                                  public string Year
                                  {
                                    get { return \_person.BirthDate.Year.ToString(); }
                                    set { d = \_person.BirthDate.AddMonths(int.Parse(value)).AddMonths(-\_person.BirthDate.Year); }
                                  }
                                  

                                  Or maybe a ValueConverter is used somewhere ? I haven't explored that yet...

                                  SledgeHammer01 wrote:

                                  Rule #1 in good software design, ESPECIALLY in WPF & MVVM... is that you should only have one instance of an object in memory at all times

                                  I do see your point with having only one instance of an object in memory at all times...especially since I have implemented object-relational mappers like Perl's Tangram. If I have two views looking at the same Model at the same time, I'd want the changes made via one view to be reflected in the other view. Right ? And binding to the Model's property instead of copying them gives me just that. Or does it ? Back to my Person.BirthDate example, suppose that I have VM1 that exposes the birth date as a single string property (BirthDate) in yyyy/mm/dd format. When the View sets the VM's BirthDate property the Model.BirthDate is updated. Now VM2 uses three string properties: Day, Month and Year. But changing the birth date via VM1 fires a "BirthDate" event that is significant only to the View that displays VM1. The change notifications are sent as changes to th

                                  S Offline
                                  S Offline
                                  SledgeHammer01
                                  wrote on last edited by
                                  #17

                                  Jean-Louis Leroy wrote:

                                  Here I stumble upon a difficulty. Consider a Person that has a birth date stored in a DateTime. Obviously we don't want to present that in the VM. Instead we want to map the double Person.BirthDate to a text input field in the view - or three text boxes for day, month and year, or some Calendar control. So what's the VM between View and Model going to look like ? Does it contain one (or three) string properties ?

                                  If you have a date and/or time, I would use a date and/or time picker and keep the value as a DateTime. Having 3 (or more) text boxes throws out a ton of functionality that you would have for free and kind of makes your app look "low budget" IMO. I do want to touch on something I said in my original response... IMO, the model should implement INPC so you CAN bind to properties in it directly. Imagine if you have 50 properties, it doesn't really make sense to wrap 50 properties just for the sake of wrapping them. Thats just a practice in typing. Unfortunately, thats not always possible. Web service proxies do not implement INPC, neither does native code, etc. There is absolutely nothing wrong with your VM exposing a Person property and your view binding to "Person.BirthDate".

                                  Jean-Louis Leroy wrote:

                                  Or does it ? Back to my Person.BirthDate example, suppose that I have VM1 that exposes the birth date as a single string property (BirthDate) in yyyy/mm/dd format. When the View sets the VM's BirthDate property the Model.BirthDate is updated. Now VM2 uses three string properties: Day, Month and Year. But changing the birth date via VM1 fires a "BirthDate" event that is significant only to the View that displays VM1. The change notifications are sent as changes to the VM's properties, whereas (if memory serves) in Smalltalk MVC they are sent as updates to the Model's properties.

                                  A properly implemented model should handle this case. Updating Day, month, year should send an INPC for Day (or month or year) AND Date. Updating the Date property should send an INPC for day, month, year and Date.

                                  1 Reply Last reply
                                  0
                                  • J Jean Louis Leroy

                                    Pete O'Hanlon wrote:

                                    Why do you think it makes modal dialogs difficult to implement? I've never found that to be the case.

                                    I suppose that many get their first exposure to MVVM via Josh Smith's article. But his sample app doesn't contain any modal dialogs. However, it's still one of the first things you need when implementing a real app. So when you turn to Google and search for "MVVM modal dialog" you get flooded with solutions falling roughly in five families: use a control; use a service; overlay a control on your view and disable its controls; what the heck, a bit of code-behind won't hurt; and finally, don't do modal, it's so nineties. It seems that no consensus has emerged on the issue yet (or I've missed it). Not that I care that much about consensus anyway, but, by design or by accident, it's a difficulty for newbies... What solution do you use ?

                                    S Offline
                                    S Offline
                                    SledgeHammer01
                                    wrote on last edited by
                                    #18

                                    I don't see why people have problems with MVVM modal dialogs. There are many times when a modal dialog is perfectly appropriate. Yes, there are many, many different opinions on how they should be done. There is really only an issue if you plan to unit test your VM. The service solution usually works quite well and keeps the testability.

                                    S 1 Reply Last reply
                                    0
                                    • P Pete OHanlon

                                      Errm. Are you 100% sure about this design approach as an absolute? How do you handle validation in this case or support for IEditableObject? The reality is, a hybrid approach will generally be necessary. In the case where you want to simply forward a property on, then your approach is fine, but where you need to validate something before it can be committed, then you should use an intermediary value. Similarly, if changes can be rolled back then you should support an intermediary value. That's the approach to use. Take the case you mentioned - where you have a huge amount of text in a model, the VM would generally do some clever processing so that only a subset of the text was kept bound to the view, virtualized in other words, and the model would be updated with the subset. In this way, the VM simply presents a snapshot of some of the text at that point in time.

                                      Forgive your enemies - it messes with their heads

                                      My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                                      S Offline
                                      S Offline
                                      SledgeHammer01
                                      wrote on last edited by
                                      #19

                                      The model should often times encapsulate all this functionality so it can be reused. Validation isn't an issue. You can handle that in the setter, or more appropriately have the model implement IDataErrorInfo.

                                      P 1 Reply Last reply
                                      0
                                      • S SledgeHammer01

                                        The model should often times encapsulate all this functionality so it can be reused. Validation isn't an issue. You can handle that in the setter, or more appropriately have the model implement IDataErrorInfo.

                                        P Offline
                                        P Offline
                                        Pete OHanlon
                                        wrote on last edited by
                                        #20

                                        Basically, with this approach, you have virtually completely defeated the whole purpose of MVVM. The point of putting this into the VM is that it is appropriate for the View and the ViewModel to interact, but you are delegating responsibility to the Model. What's the point of the VM anymore with this - it's purely acting to relay data in your approach. It's no longer adding any value.

                                        Forgive your enemies - it messes with their heads

                                        My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                                        S 1 Reply Last reply
                                        0
                                        • P Pete OHanlon

                                          Basically, with this approach, you have virtually completely defeated the whole purpose of MVVM. The point of putting this into the VM is that it is appropriate for the View and the ViewModel to interact, but you are delegating responsibility to the Model. What's the point of the VM anymore with this - it's purely acting to relay data in your approach. It's no longer adding any value.

                                          Forgive your enemies - it messes with their heads

                                          My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                                          S Offline
                                          S Offline
                                          SledgeHammer01
                                          wrote on last edited by
                                          #21

                                          I get your point, and agree to a certain extent, but also disagree to a certain extent :). Do you agree that the model should implement INPC? or do you believe that duty falls to the VM and that the model should just be a simple POCO? I think thats the models job. Why duplicate INPC code in every single VM that uses the model? If the model is already implementing INPC (and INCC), how is that any different from it implementing IEditableObject and IDataErrorInfo? I am not saying the model should handle everything, it most certainly should not. It should however encapsulate everything to do with an object so the code is centralized and not C&P'ed everywhere. The VM still has plenty to do: commands, occasional repacking of data, exposing non-model related properties, etc. The model doesn't really expose anything GUI related, thats the VMs job.

                                          P 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups