3

I am looking for advice on handling states in a WPF MVVM environment.

As an example, assume we have

enter image description here

  • A TreeView (or some other ItemsControl) with some items and
  • a button that is enabled when an item is selected.

My ViewModel contains a property SelectedItem that is bound to the SelectedItem of the TreeView.

When the Button is clicked, we change to "special state": the current SelectedItem is stored somewhere for later reference (let's call the storing variable FirstSelectedItem). Then the Selection is cleared, the Button is disabled and the user is supposed to select an item again (can be any item, even the same one). So we get some entry in SelectedItem. Then the data of the item stored in FirstSelectedItem is changed depending on SelectedItem (change some internal properties that are not visible in the view). After this is done, SelectedItem is restored to contain FirstSelectedItem, the Button is enabled and the view is in "normal state" again.

I would like to know how you approach such problems in WPF. For me it is important to use the MVVM pattern and use codebehind only to redirect stuff to the ViewModel, and that it is possible to give every UI element a different look and behaviour depending on the current state. In a more complicated example, it might be that some controls become disabled or show up or execute another command than usual when a certain state is current.

For the looks, I think a way would be to have some property State in the ViewModel. The UI elements can then somehow make their looks dependent on that state (although I don't know how, but I'm sure it's possible).

For the behaviour, I have no idea. As far as I know, a Button can bind to one Command, and only one. Or can the binding be changed depending on State?

  • 1
    _ Button can bind to one Command, and only one. Or can the binding be changed depending on State_ -> you don't need change binding. State is property of ViewModel and method which executes Command is in ViewModel. So Method will change behavior based on the State – Fabio Oct 8 '16 at 20:59
1

If I understand what you are saying, you need some UI cue to denote when the State property changes. There are many ways to do it in pure MVVM.

You could use a ValueConverter to convert the value of the state to a System.Windows.Visibility value have that bound to the visibility of certain elements in order to facilitate visibility changes based on the State property. You could do the same with a converter to convert state to a boolean in order to facilitate IsEnabled or IsReadOnly changes too.

Then, if you wanted the button command to change depending on the state you could change the binding and raise a PropertyChanged on the command for the button. Or just change the underlying method if you are using something like a RelayCommand seen here. Or you could just have a command that executes some routine that is affected by the State property. Or maybe pass in the state as a command parameter.

You could also use DataTemplates and bind a DataTemplate to the State property.

Facilitating a state change, depending on what that means, could be business logic, and that should probably not go in the ViewModel (Unless, like Rachel said, it is a very small app with limited need for abstraction). However, what you are attempting to do with the UI can be done with bindings and ViewModel property changes/notifications. There are 1,000 ways to skin a cat, you just need to find the one that best suits you.

0

From your description, it sounds like this is business logic so I would probably put that in my ViewModel/Model layer.

Something like :

public class MyViewModel()
{
    private object _first
    private object _second;

    // bind TreeView.SelectedItem to this property
    public object SelectedItem
    {
        get { return (_isSecondState ? _second : _first); }
        set 
        {
            // Personally I'd rather try to do this in a PropertyChange event than 
            // a property setter, but this is for simplicity
            if (_isSecondState)
            {
                _second = value;

                // handle whatever should happen when second is clicked
                DoSomething();

                // revert back to first state
                _isSecondState = false;
            }
            else
            {
                _first = value;
            }
        }
    }

    public ICommand MyButtonCommand
    {
        get
        {
            if (_getProductCommand == null)
            {
                _getProductCommand = new RelayCommand(
                    param => ButtonCommand(),  // execute when button clicked
                    param => !_isSecondState   // disable button if second state
                );
            }
            return _getProductCommand;
        }
    }

    private void ButtonCommand()
    {
       // setup second state
        _isSecondState = true;
        _second = null;

        // probably need something like this to requery binding
        OnPropertyChanged("SelectedItem");

        // Do whatever you want to do when button clicked
    }
}

Also about your question

As far as I know, a Button can bind to one Command, and only one. Or can the binding be changed depending on State?

It would be easy enough to make your button command behave different depending on what state your ViewModel is in.

The idea is that if this is business logic, it belongs in the ViewModel/Model layer. If it's generic View-Specific logic that could apply to any Button/TreeList/etc then you could probably code some kind of custom UI-specific behavior for it.

  • 1
    Business logic goes in the ... ViewModel? I thought business logic belonged in the Model. stackoverflow.com/a/16338888 – Robert Harvey Dec 8 '16 at 16:10
  • 1
    @RobertHarvey I suppose it depends on the level of complexity of your application. Typically my Model layer is a very dumb layer of building bricks, with no logic in them at all, and what I call ViewModels contain my business logic. I think that's probably because of the size of my typical WPF application - if I created something larger, I would probably want some kind of layer between "dumb bricks of data" and "this is what the View interacts with" to handle application logic. I'm not too sure if I'd if I'd call them "ViewModels" or "Models" but I'll update my answer :) – Rachel Dec 8 '16 at 16:15
  • For this specific case, I think this logic would make more sense in a ViewModel since it deals with how the View needs it's data for display – Rachel Dec 8 '16 at 16:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.