Having read all the StackOverflow entries regarding Model-View-ViewModel architecture along with most of the readily available resources on the net I have come to the conclusion that it is the de-facto standard for building SOLID Silverlight apps.
I started to plan my next application using this architecture. One of the requirements for the application is to build or change the visual component structure. For example, responding to user interaction I would like to programmatically append an unknown-at-compile-time number of Rectangles and Ellipses to a specific Canvas or Canvases.
I started to twist my mind to apply the MVVM pattern and think where the code responsible for attaching the new components should go. I concluded that it doesn't belong to any of the MVVM layers and therefore it is impossible to apply this architecture in scenarious where you have to manipulate the component tree at runtime.
Is there a way to still use Model-View-ViewModel in these kind of scenarious or it is only limited to work with a fixed View component structure?
MVVM separates the different components of the development process into three categories, model, view and ViewModel. This typically involves code markup or graphical user interfaces (GUI). MVC, or model-view-control is a way developers separate programs into these three components.
It is perfectly right to have ViewModel contains ViewModel. Actually that is the recommended practice: To have one main ViewModel for the whole page, the main ViewModel could contain ViewModels for the sub views in the page.
MVC Model component can be tested separately from the user, while MVVM is easy for separate unit testing, and code is event-driven. MVC architecture has “one to many” relationships between Controller & View, while in MVVC architecture, “one to many” relationships between View & View Model.
In MVP a Presenter has reference/access to the View, i.e. you can directly bind to Click events or call a control's method from the Presenter. In MVVM this isn't allowed, as this breaks it.
Don't manipulate the component tree. Instead, manipulate a model that represents the component tree. Then have your view bind to the various collections and properties in that model to produce its visuals.
What follows is a really simplified example. It just shows the concepts - please don't take it as indicative of how you should factor your code.
First, my model:
public abstract class Shape
{
public double Left { get; set; }
public double Top { get; set; }
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
}
Next, I expose a collection of said shapes (you would use another model to contain this collection). Then I bind to it in my view:
<Window x:Name="_root" x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Rectangle}">
<Rectangle Width="{Binding Width}" Height="{Binding Height}" Stroke="Black"/>
</DataTemplate>
</Window.Resources>
<ItemsControl DataContext="{Binding ElementName=_root}" ItemsSource="{Binding Shapes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Window>
The fundamental problem in your question is confusing requirements of your users (manipulating objects that are represented by rectangles and ellipses (I'm only guessing)) with implementation details (appending Rectangle
s and Ellipse
s to Canvas
es).
Again, the different responsibilities in the MVVM pattern:
Translate the ViewModel into pixels and translate input events into method calls on the ViewModel.
This would be the actual Silverlight components (Rectangle
, Ellipse
, Canvas
) binding against their DataContext
and having a few very small event handlers or Command
s or whatever.
Hold data and business logic in a domain-specific way.
This represents the "mathematical" rectangles and ellipses your users are drawing.
Refine the Model in a UI-oriented and often use-case specific way.
Here you store the transient information like "currently selected object" that are relevant for a specific view but are not attributes of the underlying Model's concept.
Read my blog for more on my views on MVVM.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With