I am trying to implement mvvm and I am struggling with a clean solution to a simple problem. The view can have 3 different states: NewEditable, DisplayOnly, Editable. The idea is that at each state a label and content of a button will change depending on a state, for example, the button will be: "Add", "Edit" and "Save" respectively.
Currently, the vm has bindable properties that update depending on the state of the control but this seems very messy especially when the rest of the logic for the vm is added. Like, it is just playing with strings.
Is there a better, cleaner way? Maybe couple converters that would take a state as input and string as output?
How do you approach changing views based on the state of a vm?
My current ViewModel just for the view logic as you can see loads of boilerplate:
public class ViewModel : NotifyPropertyChangedBase
{
public enum State { New, Edit, DisplayOnly }
public ViewModel()
{
// Set commands
Edit = new CommandHandler(param => EditAction(), () => true);
EndEdit = new CommandHandler(param => EndEditAction(), () => true);
/*
* Some more logic to set up the class
*/
}
public ICommand Edit { get; private set; }
public ICommand EndEdit { get; private set; }
public State DisplayState
{
get { return _displayState; }
private set { SetProperty(ref _displayState, value, nameof(DisplayState)); } // from the base to simply the logic
}
public string ControlTitle
{
get { return _controlTitle; }
private set { SetProperty(ref _controlTitle, value, nameof(ControlTitle)); } // from the base to simply the logic
}
public string ButtonTitle
{
get { return _buttonTitle; }
private set { SetProperty(ref _buttonTitle, value, nameof(ButtonTitle)); } // from the base to simply the logic
}
private State _displayState = State.New;
private string _controlTitle = CONTROL_TITLE_NEW;
private string _buttonTitle = BUTTON_TITLE_NEW;
public const string CONTROL_TITLE_NEW = "New Object"; // Could be removed as used once in the example
public const string CONTROL_TITLE_DISPLAY = "Display Object";
public const string CONTROL_TITLE_EDIT = "Edit Object";
public const string BUTTON_TITLE_NEW = "Create"; // Could be removed as used once in the example
public const string BUTTON_TITLE_DISPLAY = "Edit";
public const string BUTTON_TITLE_EDIT = "Save";
private void EditAction()
{
DisplayState = State.Edit;
ControlTitle = CONTROL_TITLE_EDIT;
ButtonTitle = BUTTON_TITLE_EDIT;
// Some business logic
}
private void EndEditAction()
{
DisplayState = State.DisplayOnly;
ControlTitle = CONTROL_TITLE_DISPLAY;
ButtonTitle = BUTTON_TITLE_DISPLAY;
// Some business logic
}
/*
* Rest of the logic for the class
*/
}
There is multiple approaches to this problem.
I would choose 1st solution, unless your viewModel is +500 rows and it is hard to maintain
If you want to change views depending on viewmodels, I would suggest to read about DataTemplate and DataType. But in this approach would be 1 parent viewModel, which holds what state it should show, and 3 child viewModels. Then you create parentView and inside control with binded current viewModel (one of 3) and with datatypes it will display correct view