-1

As far as I know, the default way to use a ObservableCollection that is bound to a listview is with model classes as elements (ObservableCollection<MyModel>). So when a listview element is selected, we use NavigateAsync and pass the model, which then can be used by the ViewModel to "fill itself". The problem with this approach is, that it's not possible to use ViewModel properties for binding in the listview.

For example: I have a View, ViewModel and Model "PickList", which contains a collection of "PickLine" objects - each having a View, ViewModel and Model themselves. The PickLine object contains a property "PickedQuantity" and a property "OpenQuantity". Now in my PickList view, I don't want to bind these two to separate items (e.g. two labels), but I want to have one label to display both I a format like for example "PickedQuantity / OpenQuantity". I know this example can be solved by using multi binding or something like this. But that's not the meaning of it all. My PickLine ViewModel already has a property "QuantityString", that I want to bind to the label of a listview element via DataTemplate. But how can I do this. Is it even possible?

Christoph Mett
  • 369
  • 3
  • 16
  • Don't you mean `... with view model classes.` in your first sentence? Binding directly to the models is rarely a good idea. – Haukinger Jan 19 '19 at 14:42
  • @Haukinger it meant with model class elements. So ObservableCollection. I'm editing it for clarification. – Christoph Mett Jan 19 '19 at 16:26

2 Answers2

0

Make a property that combines the two other properties and bind to that. E.g.:

public string FullQuantity {get {return $"{PickedQuantity} / {OpenQuantity}";}}

Then in the setter for PickedQuantity and OpenQuantity, you will want to call whatever PropertyChanged method you have set up to notify the bindings of a property change and pass in the FullQuantity property name so elements that are bound to FullQuantity get updated when either PickedQuantity or OpenQuantity are changed.

This way, you are only binding one label's text to one property and that label would get updated when either of the two quantity properties are changed.

Note: I am unfamiliar with Prism, but this approach should work regardless of the Mvvm framework in use.

jgoldberger - MSFT
  • 5,978
  • 2
  • 20
  • 44
  • But this would mean, that my model has a property that is only needed in the view. Isn't that totally against MVVM? Aren't view models exactly for this? – Christoph Mett Jan 19 '19 at 16:13
  • Yes, I meant you make that composite property in your view model for the view. – jgoldberger - MSFT Jan 23 '19 at 04:13
  • Yes, that's how it's be done in "simple" MVVM. But Prism uses View first navigation, so I have to initialize the ViewModel for myself (not that of a problem) and in the best way use this ViewModel for the view I am navigating to, when a line is clicked. And this is what doesn't seam to work in Prism. – Christoph Mett Jan 23 '19 at 07:05
-1

Your PickListViewModel should expose a collection property whose items are of type PickLineViewModel (not PickLine).

Whether you need an ObservableCollection<PickLineViewModel> depends on where changes can happen - in service / model that initially created the PickLines or in the GUI or both. In any way, you have to make sure the changes are propagated from one side (the collection of view models) to the other (the collection of models). Google wrapping observable collection as a starter (hint: avoid two-way sync if possible). These blog posts are old but still relevant and make a good reading. A trivial wrapping is described in this answer.

Haukinger
  • 10,420
  • 2
  • 15
  • 28
  • For "simple MVVM" this ist totally right. But the problem is, that this is not the way Prism works. Prism uses models in collections and when a list element is clicked a new view is created, the ViewModelLocator finds and instantiates the ViewModel and passes parameters like the model to it. So how could a collection of ViewModels be realized with Prism in mind? – Christoph Mett Jan 19 '19 at 16:23
  • The `ViewModelLocator` is purely optional. It makes view-first navigation simple, but in view model first-navigation it is not used. You use view first for the most high-level navigation when there's no context (one screen to another), but within a screen, your view models expose othe view models through properties, and the framework fetches the associated data templates. – Haukinger Jan 21 '19 at 12:09
  • Okay, thank you very much, @Haukinger. That already helps me a lot. But if I have the ViewModel instance before navigating, can I than pass the instance while navigating, so Prism won't try to find the ViewModel to the view I am navigating to but instead uses the instance I already have? – Christoph Mett Jan 21 '19 at 17:25
  • It will work the other way round. If you already have the view model instance, you just publish a property changed event on the property that exposes that instance and the bound content control will automatically update with the new data template. – Haukinger Jan 22 '19 at 09:23
  • Ah, I didn't explained it correctly. I didn't meant how the ViewModel can be used in my PickList(ViewModel). I meant if for example I click a row in my pick list, the app navigates to the corresponding view. If I use NavigationService.NavigateAsync Prisms ViewModelLocator will find the ViewModel class to the PickLine View, instantiates it, set it as BindingContext and show the view. But how can I tell Prism not to search for the ViewModel and instantiate it on navigating, but to navigate to the view and use the ViewModel I already have in my ObservableCollection of the PickList ViewModel? – Christoph Mett Jan 22 '19 at 13:30
  • That may indeed be difficult, as prism's navigation service doesn't seem to support that. I would navigate to the "Show-the-details-of-my-PickLine" page and pass the id of the pick line as parameter so that the detail page can fetch the instance from the same service the original list page got it from. – Haukinger Jan 22 '19 at 14:25
  • What do you mean with "fetch the instance from the same service the original list page got it from"? – Christoph Mett Jan 23 '19 at 07:09
  • The page containing the pick list doesn't invent the contents of the pick list, it gets them from some repository. The page you're navigating to can fetch the single pick line model from the same service if it gets an id during the navigation. – Haukinger Jan 23 '19 at 08:21
  • Ah, yes, that's how I do it at the moment. I would prefer to just pass the ViewModel instance to the View, so another call to my repository wouldn't be necessary, but as we figured out, this is sadly most likely to be impossible. – Christoph Mett Jan 23 '19 at 09:09