1

I need to set a mode in one view from a different view. Trying to stay organized with MVC. Looking at answer at Invoke model logic in one UserControl from view-model in another UserControl without violating MVVM, but

  • It seems redundant for a controller to update its view AND fire a signal for anything else to respond to; so, is it better for View1 to emit the signal/event? Or, should model fire it?

  • Who owns the signals?

  • Signals can be especially dangerous when it comes to collaborative software development (codebase becomes chaos quickly, people get lazy and just fire signals all over the place). What's a solid pattern such cases?

Some code:

class View1 {
 ...
 clickModeOption(e){ 
   this.controller.onSelectSomeMode(e.value); //or, should I call View2's controller?
                                              //or, should I emit the signal myself?
 }
 ...
}

class Controller1 {
  ...
  onSelectSomeMode(mode) {

    model.someMode = mode; //i.e. maybe act on model here

    //these two lines look redundant of each other:
    this.view.setSomething();
    somebodysSignals.modeChanged.fire(); //or, model can fire
  }
}

class View2 {
  constructor(signals) {
    ...
    this.signals.modeChanged.add((newMode)=>this.setMode(newMode)); // i'm a cowboy
  }
  ...
  setSomeMode(mode) {...} //my controller isn't calling this :/
}

1 Answer 1

2

The question you linked to explicitly discusses WPF and MVVM, but you didn't mention whether or not you're using these. If you do happen to be using any of the XAML-based UI frameworks (UWP, Xamarin, WPF, etc.), then you should consider looking at the MVVM pattern and investigate supporting libraries such as Prism, Caliburn Micro or MVVM Light which will eliminate a good chunk of boilerplate related to INotifyPropertyChanged.


  • It seems redundant for a controller to update its view AND fire a signal for anything else to respond to; so, is it better for View1 to emit the signal/event? Or, should model fire it?

Almost certainly the latter. The 'Model' in any MV* pattern is typically available to be updated from other parts of the application (maybe even from a non-UI element such as a network socket), so really the only sensible place to fire the signal would be within the model, because you certainly do not want something like a network object to have visibility of either your View or your Controller.

That way, in the worst-case scenario (i.e. one where there are no facilities available in the UI framework to reduce the boilerplate) the controller is responsible for updating the View by subscribing to changes in the model, which may be triggered from the View, or a different View, or some external mechanism.

  • Who owns the signals?

  • Signals can be especially dangerous when it comes to collaborative software development (codebase becomes chaos quickly, people get lazy and just fire signals all over the place). What's a solid pattern such cases?

Ideally, the model should own both the state and the signal, encapsulated inside some kind of observable library object to eliminate boilerplate code and prevent the signal being either abused or forgotten.

To elaborate on that somewhat, the push capability of the signal should be the sole reserve of the 'setter' method for the state. The only time that signal should ever be raised is when any part of the application has updated the data - it makes sense to create a very tightly-coupled relationship between the model state and its signal; it's usually undesirable to fall back onto any kind of solution which involves using one without the other.

Conversely, the pull capability is fair game; any part of the application might reasonably want to know when the model state has changed, so there's no real benefit in restricting access to potential subscribers. This is another reason why the signal should be tightly coupled to the state, because anything subscribing to that signal should be allowed to make the assumption that it will receive all state changes, and that a received signal means the state has changed.


From a practical point of view, this problem has been solved many times over, albeit in different ways by different UI frameworks, so the best way for you to deal with this depends heavily on the UI framework that you're using.

In the ideal scenario, it'd be a UI framework which supports Data binding in which case the amount of Controller boilerplate will be reduced, or maybe even eliminated altogether in some newer frameworks which have been designed with MV* in mind from the outset.

A UI framework which supports data binding will take care of synchronising changes between the View and the Model with little or no code whatsoever in the controller, assuming that a suitable observable/notification mechanism exists in the Model.

If Data binding isn't available in your UI framework, then you can replicate the approach in the Controller yourself, and save yourself the hassle of reinventing the signal mechanism by using something like Reactive Extensions (Rx).

Simple example for a UI framework which doesn't have data binding built-in, using the BehaviourSubject concept in Rx:

// Model shared by multiple Views
class MyModel {
    data = new BehaviourSubject<String>("");

    updateData(s: string) {
        this.data.next(s);
    }
}

// Controller for View1 - Repeat as necessary for View2, View3, etc.
class Controller1 {
    constructor(view, model) {
        // Update the view when the data changes
        model.data.subscribe(d => view.setText(d));

        // Update the data when the view changes
        view.textBox1.onTextChange(text => model.updateData(text));
    }
}

The Rx BehaviourSubject is a stateful observable object which must also be given an initial state - i.e. it combines the model state and the signal, but the push capability for the signal is hidden.

If neither Rx nor any similar equivalent happens to be available for the language you're using, then it should be reasonably simple to replicate a simple variation on BehaviourSubject for yourself.

13
  • Thank you for the amazing answer. Controller subscribing to model answers my problem. I have no framework with data binding (app is React/THREE.js hybrid), so I will organize following BehviourSubject. Mar 25, 2018 at 13:01
  • is Redux considered to be a data binding solution? I have been using it, but my impression is that it does the opposite: it facilitates view-model subscriptions, but not deeper model layer observation... Mar 25, 2018 at 18:37
  • @user2132190 React isn't really designed for two-way data binding - its creators had a preference for the Flux pattern/Redux. Flux/Redux is intended to solve your original problem of communicating between multiple components however; the 'store' allows many components to subscribe to changes - although there's more code/boilerplate involved in creating and dispatching Actions. Mar 26, 2018 at 16:42
  • Also, react supports one-way data binding out of the box; so if the component subscribes to state changes, then React is already capable of watching for changes in the state - stackoverflow.com/questions/38332912/… Mar 26, 2018 at 16:43
  • Yes but I see React/Redux as providing observer mechanism for view state only; in other words, the local state of a React component and/or the Redux store are no place for my model-layer state...React+-Redux only gives you half of the above infrastructure. . .the views are watching for changes in their state so they can re-rerender; but, the controlling Redux actions/reducers still need to subscribe to model-layer events in order to trigger view changes (in my way of looking at things). Other opinions would be greatly appreciated however :) Mar 26, 2018 at 18:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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