What I want to be able to do is when the user taps on a list item, it replaces the labels on that item with either a picker or text box and provides a "Save" button. Once the user makes changes and clicks Save, the list updates and restores to the original format (all labels).

I'm using MVVM. Is this possible? Does the ListView have an Edit template or something similar?
Is there a more standard way of doing this (editing an item)?
With MVVM, how can I tell which item was tapped?

I'd prefer not to bring up a whole second screen. Thanks for your time.

Best Answer

You should not know the "controls". You should know the "property". In your ViewModel you should have a property (for esample "IsTapped") that you set to "true" when your item is Tapped. If you bind "IsTapped" to your Button's "IsVisible" property, it becomes visible

@AlessandroCaliaro said:
Yes it’s possible. You should have in your ViewCell the Picker, the Button and the Entry with IsVisible property set to false. When you tap the row, you can set the IsVisible property to true.

Thanks for the suggestion. Sorry to ask, but how do I identify which controls I need to toggle? The ItemtappedEventArgs Item gives me the item tapped, but how to I find the controls? Also, I'm assuming I should be doing this in the form's code behind rather than the ViewModel.

You should not know the "controls". You should know the "property". In your ViewModel you should have a property (for esample "IsTapped") that you set to "true" when your item is Tapped. If you bind "IsTapped" to your Button's "IsVisible" property, it becomes visible

For an MVVM friendly approach, you should look at Data triggers, convertors and behaviors to accomplish this.

In this scenario you just need to ensure your bound class has an edit model flag or something as a boolean that you can use to trigger the UI changes which you can do with either visibility.

You can use behaviors to hook into the Listview's tapped event as suggested and pass the selected row to the viewmodelvia a command binding and set the boolean state there, you'll probably have to make a linq query to your OC to switch of any other rows in edit mode and if your class implements change tracking you may want to ask before wiping changes.

I would suggest this is not not the usual behavior for an app, A Listview tap (especially if the listitem is highlighted) usually indicates a navigation event should take place.

@AlessandroCaliaro said:
You should not know the "controls". You should know the "property". In your ViewModel you should have a property (for esample "IsTapped") that you set to "true" when your item is Tapped. If you bind "IsTapped" to your Button's "IsVisible" property, it becomes visible

Agreed. Controls should stay with the view. However, if all the hidden controls are bound to the same "IsTapped", wouldn't the controls in all rows be toggled? I'm only wanting the control in the row that was tapped to become visible. Perhaps if you provide a code sample that would help me understand.

For an MVVM friendly approach, you should look at Data triggers, convertors and behaviors to accomplish this.

In this scenario you just need to ensure your bound class has an edit model flag or something as a boolean that you can use to trigger the UI changes which you can do with either visibility.

You can use behaviors to hook into the Listview's tapped event as suggested and pass the selected row to the viewmodelvia a command binding and set the boolean state there, you'll probably have to make a linq query to your OC to switch of any other rows in edit mode and if your class implements change tracking you may want to ask before wiping changes.

I would suggest this is not not the usual behavior for an app, A Listview tap (especially if the listitem is highlighted) usually indicates a navigation event should take place.

This approach sounds very complex. Converter? What would I be converting? Ideally I'd like to find a "simple" solution if possible.

Another approach I saw was to trap the tapped event in the view's code behind, then use ContainerFromItem on the list view to find the specific container then update the controls. However, it looks like ContainerFromItem doesn't exist anymore (at least it's showing as undefined when I try it). I'm fine with doing everything in the view since swapping controls has no impact on the ViewModel until after they click save.

If you define your custom ViewCell in a separate xaml/xaml.cs file rather than in your ListView xaml, you can override the Tapped method in the xaml.cs file. From there you are in the particular ViewCell you are wanting and can show/hide controls or set a IsVisible property on your Model object that is the BindingContext to your ViewCell.

While the comment I posted above might work, it isn't good practice and doesn't comply with MVVM. I agree with @NMackay and suggest a different approach to this using data triggers and such to accomplish what you want. Try his suggestions and post example if able to.

For an MVVM friendly approach, you should look at Data triggers, convertors and behaviors to accomplish this.

In this scenario you just need to ensure your bound class has an edit model flag or something as a boolean that you can use to trigger the UI changes which you can do with either visibility of > @EdDhalsim said:

For an MVVM friendly approach, you should look at Data triggers, convertors and behaviors to accomplish this.

In this scenario you just need to ensure your bound class has an edit model flag or something as a boolean that you can use to trigger the UI changes which you can do with either visibility.

You can use behaviors to hook into the Listview's tapped event as suggested and pass the selected row to the viewmodelvia a command binding and set the boolean state there, you'll probably have to make a linq query to your OC to switch of any other rows in edit mode and if your class implements change tracking you may want to ask before wiping changes.

I would suggest this is not not the usual behavior for an app, A Listview tap (especially if the listitem is highlighted) usually indicates a navigation event should take place.

This approach sounds very complex. Converter? What would I be converting? Ideally I'd like to find a "simple" solution if possible.

Another approach I saw was to trap the tapped event in the view's code behind, then use ContainerFromItem on the list view to find the specific container then update the controls. However, it looks like ContainerFromItem doesn't exist anymore (at least it's showing as undefined when I try it). I'm fine with doing everything in the view since swapping controls has no impact on the ViewModel until after they click save.

Not complex but whatever works for you, you can write your own custom data template or subclass the listview control, data binding in Forms is powerful though and can save you a lot of effort.