Code structure for simple drawing apps when using MVVM / MVVMLight
Code structure for simple drawing apps when using MVVM / MVVMLight
I'm currently using the MVVM
pattern in one of my apps, to be more specific I'm using the MVVMLight
framework. In one of the pages, I will have a screen where the user can input the width
and length
to draw rectangles, there is not much code logic so, I was thinking to put all of my code in the code-behind since most of what will be happening in this screen is UI related.
MVVM
MVVMLight
width
length
Does that make sense to use the code-behind in this case? If not, how would you structure the code to use the MVVM pattern, what would you put in the ViewModel
in this case and what would you put in your code behind?
ViewModel
Here is the code without using MVVM.
<Window x:Class="DrawingRectangles.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DrawingRectangles"
mc:Ignorable="d"
Title="MainWindow" Height="531.798" Width="782.115">
<Grid Name="MyGrid" Width="480" Height="240" Margin="27,23,267,174">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="59*"/>
<ColumnDefinition Width="421*"/>
</Grid.ColumnDefinitions>
<Canvas Name="MyCanvas" Background="#FFF1F0F0" Margin="10" Grid.ColumnSpan="2"/>
<Grid Margin="10,235,10,-92" Background="WhiteSmoke" Grid.ColumnSpan="2">
<Button x:Name="drawButton" Content="Draw" Click="drawButton_Click"/>
<Button x:Name="resetButton" Content="Reset" Click="resetButton_Click"/>
<TextBox x:Name="textBoxPartWidth"/>
<TextBox x:Name="textBoxPartLength"/>
</Grid>
</Grid>
</Window>
namespace DrawingRectangles
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void drawButton_Click(object sender, RoutedEventArgs e)
{
clearScreen();
int xParts = 10;
int yParts = 10;
for (int i = 0; i < xParts; i++) {
for (int j = 0; j < yParts; j++) {
// Create a rectangle.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = Convert.ToDouble(textBoxPartLength.Text);
myRectangle.Height = Convert.ToDouble(textBoxPartWidth.Text);
myRectangle.Margin = new Thickness((Convert.ToInt32(myRectangle.Width) + 1) * i, (Convert.ToInt32(myRectangle.Height) + 1) * j, 0, 0);
myRectangle.Fill = new SolidColorBrush(Color.FromArgb(170, 51, 51, 255));
MyCanvas.Children.Add(myRectangle);
}
}
}
private void resetButton_Click(object sender, RoutedEventArgs e)
{
MyCanvas.Children.Clear();
}
private void clearScreen()
{
MyCanvas.Children.Clear();
}
}
}
EDIT:
Second Image (reference only):
You can start here to see how to use canvas in mvvm.
– Sinatr
Jul 2 at 13:44
Also take a look at this: stackoverflow.com/a/40190793/1136211
– Clemens
Jul 2 at 13:46
Thank you both for the good info.
– fs_tigre
Jul 2 at 13:48
1 Answer
1
The Button
in the view should be bound to an ICommand
property of the view model. The command will be executed when you click on the Button
. Please refer to this blog post for information about how to handle events in an MVVM application. In MvvmLight, the ICommand
implementation is called RelayCommand
.
Button
ICommand
Button
ICommand
RelayCommand
You should also bind the Text
properties of the TextBoxes
to two source properties of the view model and the Canvas
element in your view should be replaced with an ItemsControl
that you bind to a collection of objects that are defined in the view model.
Text
TextBoxes
Canvas
ItemsControl
Please refer to the following sample code.
Model:
public class Model
{
public int Width { get; set; }
public int Height { get; set; }
public Thickness Margin { get; set; }
public Brush Fill { get; set; }
}
View:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="#FFF1F0F0" Margin="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="{Binding Width}"
Height="{Binding Height}"
Margin="{Binding Margin}"
Fill="{Binding Fill}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Draw" Command="{Binding DrawCommand}" />
<Button Content="Reset" Command="{Binding ResetCommand}" />
<TextBox Text="{Binding Width}"/>
<TextBox Text="{Binding Height}"/>
View Model:
public class ViewModel
{
public ViewModel()
{
DrawCommand = new RelayCommand(Draw);
ResetCommand = new RelayCommand(Clear);
}
public ObservableCollection<Model> Items { get; } = new ObservableCollection<Model>();
public RelayCommand DrawCommand { get; }
public RelayCommand ResetCommand { get; }
public int Width { get; set; }
public int Height { get; set; }
private void Draw()
{
Clear();
int xParts = 10;
int yParts = 10;
for (int i = 0; i < xParts; i++)
{
for (int j = 0; j < yParts; j++)
{
Model model = new Model();
model.Width = Width;
model.Height = Height;
model.Margin = new Thickness((model.Width + 1) * i, (model.Height + 1) * j, 0, 0);
model.Fill = new SolidColorBrush(Color.FromArgb(170, 51, 51, 255));
Items.Add(model);
}
}
}
private void Clear()
{
Items.Clear();
}
}
In this example all application logic has been moved to the view model where it belongs. There is no logic left in the code-behind class of the view.
Also note that the view models creates instances of Model
objects rather than creating Rectangle
elements. It's generally considered be a bad practice to reference UI elements in a view model class. The Rectangle
elements are created by the ItemsControl
. See the ItemTemplate
in the view.
Model
Rectangle
Rectangle
ItemsControl
ItemTemplate
Thanks a lot for the code example!
– fs_tigre
Jul 2 at 15:21
you are creating multiple
new SolidColorBrush(Color.FromArgb(170, 51, 51, 255))
in a view model when SolidColorBrush is a UI element. it is a bad practice– ASh
Jul 2 at 15:28
new SolidColorBrush(Color.FromArgb(170, 51, 51, 255))
have you linked your own blog? if yes, then it will be a good idea to disclose that.
– ASh
Jul 2 at 15:29
@fs_tigre: Fixed.
– mm8
Jul 4 at 14:48
@fs_tigre: Please ask a new question if you have another issue.
– mm8
Jul 5 at 14:00
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Generally speaking in MVVM button click = command and text fields = bindings to properties in view model. Your aim to have zero code behind and it seems it's possible for your task.
– Sinatr
Jul 2 at 13:40