Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switching between view mode and edit mode in MVVM?

I am new to MVVM and I've decided to move on and start adopting it in my upcoming projects.

I have read this related question and answer, but I don't know how this would be implemented with MVVM.

I want all the views in my project to have 2 modes, Edit Mode and View Mode.
I don't want the user by default to see TextBoxes for all the fields, I rather want them to see TextBlocks (or set all the TextBoxes' as IsReadOnly property to true (via style etc. you tell me..).

When the user opens up the entity it should usually be TextBlocks, Labels (or readonly TextBoxes) etc., and if he clicks "Edit" (if he has permission to), it should go Edit Mode, and all the fields' labels should be inverted to TextBoxes (RichTextBoxes etc., ComboBoxes or any other editable fields that are not just labels).

I am pretty sure I am not the only one having this issue, I would like to hear from the experts what is the most efficient way to switch between these modes in pure MVVM, and whether it's is common to declare two separate views for it.

Please refer me to a good article that explains how to do it (maybe it is done by Visual State?? IDK).

UPDATE
I want to know WHAT rather than HOW, my question is about the pattern, and is should I separate Edit Mode from View Mode at either the V or the VM? So please emphasize this detail in your answer.

Thanks in advance.

like image 487
Shimmy Weitzhandler Avatar asked Feb 06 '11 23:02

Shimmy Weitzhandler


3 Answers

Use the IsReadOnly property for your text boxes and bind that to the "edit mode" property:

<TextBox .... IsReadOnly={Binding IsViewMode} ... />

Then in your view model:

public bool IsViewMode
{
    get { return _IsViewMode; }
    set
    {
        _IsViewMode= value;
        // Call NotifyPropertyChanged when the source property is updated.
        NotifyPropertyChanged("IsViewMode");
    }
}

IsViewMode defaults to true and is switched to false when the user clicks "edit". The binding will instantly make all the text boxes editable.

You could do the same for the other controls - though it will be the IsEnabled property you need to bind to in these cases - though you'd have greyed out controls.

To swap out text blocks and your controls you'll need to have both controls sharing the same location in a grid and their visibility controlled by the IsViewMode property via a pair of converters:

<TextBlock Grid.Row="1" Grid.Column="2" ...
           Visiblity={Binding IsViewMode, Converter=DirectConverter} ... />
<ComboBox Grid.Row="1" Grid.Column="2" ...
          Visiblity={Binding IsViewMode, Converter=InvertedConverter} ... />

The direct converter is:

return IsViewMode ? Visibility.Visible : Visibility.Collapsed;

The inverted converter is:

return IsViewMode ? Visibility.Collapsed : Visibility.Visible;
like image 83
ChrisF Avatar answered Nov 03 '22 10:11

ChrisF


I think about it this way: the View is what it looks like, and the ViewModel is how it interacts with the user. Since a readonly interface has substantially different behavior than a read/write interface, then there should be two different ViewModels.

Now I did created an edit ViewModel that inherited from a display ViewModel because I considered the editing functionality to be an extension of the display functionality. This works for simple CRUD type applications where the user is directly editing fields without a lot of business logic.

On the other hand, if you have a more complicated business process (or workflow) that you're modelling, then typically the way you manipulate information is very different from the way you want to view it. Therefore, I would generally separate the two ViewModels unless it was just CRUD.

like image 24
Scott Whitlock Avatar answered Nov 03 '22 08:11

Scott Whitlock


ChrisF's answer is fine if you want to go the IsReadOnly route. If you want to go the TextBlock-to-TextBox route, though, the most efficient way is have a Control which switches its Template, via triggers, based on the value of an IsInEditMode or IsInViewModel property.

like image 36
HappyNomad Avatar answered Nov 03 '22 10:11

HappyNomad