Search code examples
wpfmvvmdatatemplateadorner

WPF: Adorning a ViewModel?


I have these ViewModels: RecordViewModel, ComponentViewModel where RecordViewModel essentially is a container for several ComponentViewModels.

The display of these ViewModels is currently handled by DataTemplates that look something like this:

<DataTemplate DataType="{x:Type vm:RecordViewModel}" >
    <ItemsControl ItemsSource={Binding Components} />
</DataTemplate>

<DataTemplate DataType="{x:Type vm:ComponentViewModel}" >
    <TextBox Text={Binding Name} />
</DataTemplate>

What I wanted to provide now is a way to change the order the ComponentViewModels are displayed and to remove a certain ComponentViewModel from the list. I started out doing that by manipulating the DataTemplate of the ComponentViewModel and adding buttons that provided these functions (the click would then trigger a method on the ComponentViewModel that would (through a reference "Parent" to the RecordViewModel) call a method on the RecordViewModel to perform the operation (like component.Parent.DeleteComponent(this)).

The problem with this in my oppinion is that it is really the Record that should manipulate the Components position/remove a Component and not the Component itself.

So I thought about using an adorner that attaches to the RecordViewModel and renders the buttons to provide the functionality (remove, move up, move down) for each of the ComponentViewModels.

The problem however is that these adorners need to take a reference to a Control-derivate which they adorn (which was ok I would just bind to the ItemsControl in the Record-DataTemplate) however the problem appears when I want to show the buttons in the right position for each ComponentViewModel. I only have a reference to the given ComponentViewModels and not to their visual representation (the thing defined in the DataTemplate) so I have no way of knowing where to place the 3 buttons.

Is there a way to work around this? Or is it possible that for these requirements using ViewModels/DataTemplates is just not a good idea and should I therefore use Control-derivates/ControlTemplates?

Thanks in advance!


Solution

  • Coming up with wacky architectural hacks that you can employ to keep your view model elegant and simple is missing the point. The view model is the wacky architectural hack.

    The only reason - seriously, the only reason - that the view model exists is to model the view. Does the view have buttons that trigger commands? The commands belong in the view model.

    Thinking, "it's really the Record's responsibility to move Components" seems sensible on its face, but it's actually an indication that you're losing track of why you even created a view model in the first place. Does the Component view have a "Move Up" button? Then the Component view model needs a "Move Up" command that you can bind the button to. Because that's what the Component view model is for.

    I'm being emphatic about this because this is the third or fourth question I've seen this week from WPF developers who seem to have gone down so deeply down the rabbit hole of the MVVM pattern that they've forgotten why it exists.