Setting DisplayName in Screen ctor

Topics: Extensibility, Feature Requests
May 22, 2012 at 2:05 AM

We've encountered a problem with setting DisplayName in `Screen..ctor` since we override it in a subclass of `Conductor.Collection<T>.OneActive` and the class is not fully initialized when it is set, leading to the kinds of problems seen when calling virtual members in object contructors.

We're left with three immediate choices, none of which are ideal: reimplement significant parts of `Conductor.Collection<T>.OneActive` to avoid calling the base ctor, filter out calls to `DisplayName` setter from `Screen`, or maintain patches to Caliburn.Micro. We've done the latter and it wasn't popular, so we're going with #2.

Might I suggest a redesign for this property set in the ctor? Since Screen is such an important base class, calling virtual methods in the ctor is a dangerous design. What about making the DisplayName value a parameter in the ctor? This would at least give the option to the implementor to call the ctor with the desired behavior. This would be a breaking change though. Another option would be to refactor the `Conductor.Collection<T>.OneActive` to a non-virtual protected method, say `Init()` which could be used when not calling the `Conductor.Collection<T>.OneActive` ctor.

May 23, 2012 at 2:17 PM

Overriding the Initialize method is not an option? I know that this would leave parts of the class uninitialized as long as the view model is Activated the first time, but I suppose that the DisplayName is meaningful only when displayed...

Other options require modifications to CM code base, and should be pondered by CM developes... for the sake of the discussione, here are a couple of options:

  1. Create a virtual method (OnInitialize? Configure? Prepare?) and call it in the Screen constructor, so that implementors can override Screen initialization;
  2. Avoid to set the DisplayName property directly, letting the property return the 'default' value only if the property has not been set, like this:
    private bool _isDisplayNameSet = false;
    
    private string _displayName;
    
    public string DisplayName
    {
          get { return _isDisplayNameSet ? _displayName : GetType().FullName; }
          set { 
                  if(!string.Equals(_displayName, value))
                  {
                       _displayName = value;
                      _isDisplayNameSet = true;
                      NotifyOfPropertyChange(()=>DisplayName);
                  }
               }
    }