2

I have a Window class that represent desktop windows, and some of them can be titled via a wrapper (TitledWindow), and some of them can be on top of others, also via a wrapper (TopWindow).

UML View

Now, I'm trying to create a view-model for a Window, and I want it to support those three interfaces (IWindow, ITitledWindow and ITopWindow). It looks like this:

public class WindowViewModel : ITopWindow, ITitledWindow
{
    private readonly IWindow _window;

    public WindowViewModel(IWindow window)
    {
        _window = window;
    }

    public IntPtr Handle
    {
        get { return _window.Handle; }
    }

    public Boolean? IsTopmost
    {
        get
        {
            var thisTopWindow = _window as ITopWindow;
            if (thisTopWindow == null)
                return null;
            return thisTopWindow.IsTopmost;
        }
        set
        {
            var thisTopWindow = _window as ITopWindow;
            if (thisTopWindow != null)
                thisTopWindow.IsTopmost = value;
        }
    }

    public String Title
    {
        get
        {
            var thisTitledWindow = _window as ITitledWindow;
            return thisTitledWindow == null ? null : thisTitledWindow.Title;
        }
    }
}

This is how I get the view-models:

public IList<WindowViewModel> OpenWindows
{
    get
    {
        var windowViewModels =
            from window in _windowEnumerator.EnumerateWindows()
            let titledWindow = new TitledWindow(window, _windowTitleReader)
            let topWindow = new TopWindow(titledWindow, _topmostManager)
            select new WindowViewModel(topWindow);
        return windowViewModels.ToList();
    }
}

The issue is that I can only get the 1st wrapper in the hierarchy.

All the windows in OpenWindows are also ITopWindow, but are not ITitledWindow because it wraps it inside in a private readonly field (which should probably remain this way).

The only solution I have in mind is to introduce a class that will union them (like TitledTopWindow) but I'll have to make it for every variation of a window and that's too messy (especially later when I introduce new wrappers to introduce new functionality).

What's the proper way to do it?

Update:
In my searched I've read that you use wrappers to extend functionality, but not to extend the API (which is a goal here).

So if this issue can't be addressed in the way I've intended it to, how can I add functionality in this way?

MasterMastic
  • 20,711
  • 12
  • 68
  • 90
  • If your sample is close to what you are trying to achieve consider containment instead of inheritance: window can have list of instances of "traits" that are searchable by interface. – Alexei Levenkov Oct 27 '13 at 19:43
  • Is it imperative to keep those interfaces separate? If not, you could collapse them into Window, providing a default/fallback implementation (NotImplementedException if necessary) for all operations, introduce an intermediate wrapper class which delegates all optional operations to the wrapped instance and let your concrete wrappers inherit from it. The concrete classes then override the methods belonging to the respective feature. (see also [Decorator pattern](http://en.wikipedia.org/wiki/Decorator_pattern)) But as you can image, this still has its own downsides. – JayK Oct 27 '13 at 20:26
  • @AlexeiLevenkov I'd appreciate an example or a good reference. – MasterMastic Oct 27 '13 at 21:08
  • @JayK Collapsing the interface into `Window` isn't an option. and as you can see, wrappers/decorators are already being used.. that's where the problem lays. – MasterMastic Oct 27 '13 at 21:11

1 Answers1

2

My suggestion was something along the lines of

 class Window
 {
     List<object> traits;  

     T GetTrait<T>() 
     {
        return traits.Where(t => t.GetType() == typeof(T)).FirstOrDefault();
     } 
 }

 Window w;
 var topLevel = w.GetTrait<TopLevel>();
 if (topLevel != null)....

But this suggestion requires serious reworking of the interfaces/code.

I think you really want something like following invalid code so you can add as many wrappers as you want and still let all interfaces to be visible on final class:

 class TopLevel<T> : T where T:Window

I don't think you can directly achieve that (since you can't derive template class from its template parameter).

One way around is to generate derived class at runtime adding necessary interfaces and proxying all interfaces implemented by inner class. Possible approaches discussed/linked in Dynamically creating a proxy class (i.e. this A simple Dynamic Proxy).

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179