Say I have a TabControl that is presenting a collection of Foo objects (each through a FooViewModel). At the end of the list of tab items, I want a faux tab item that doesn’t model anything, but which creates a new model item and adds it to the collection when clicked.
If the concept isn’t clear, a real example is the tabs in Internet Explorer. It has n+1 tab items: n which have page content, and the last one which adds a new ‘real’ tab.
What’s the correct way (if any) to model this type of interaction in MVVM? The options I’ve thought of are:
-
Make it part of the view model. At the end of the
IEnumerable<FooViewModel> Fooscollection that the control is bound to, add a ‘new item’ sentinel and build the ‘am I a real foo or a new foo sentinel’ logic into the view model. -
Make it wholly part of the view. Re-template (and/or subclass)
TabControlto present all the real items and then also a button which invokes the command to create and insert a new item.
The first option feels wrong at first, like it’s leaking view details into the view model (it seems quite likely that ‘add a new Foo‘ is a general command, and some view may not want it invokable from the tab list at all). But it does make some amount of sense, because for the initialization process I’ll already need to model a ‘semi-constructed Foo‘, so a model of a ‘not-yet-existing Foo‘ doesn’t seem so far off.
The second part seems like a lot of work and also easy to screw up (assuming the desire is for it to look and feel like the other tabs).
But I’m new to MVVM; surely this comes up pretty often. Maybe I’m missing something entirely. What’s the traditional way to deal with it?
A couple of the key tenants of the MVVM pattern are:
Which of your suggestions best fulfills the above? I would say option (1). You can write unit tests to ensure that the last item in the list is always a ‘sentinel’ item.
In order to “build ‘am I a real foo or a new foo sentinel’ logic into the view model.”, you can simply use typed DataTemplates.