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();
}
}
}



enter image description here



EDIT:
Second Image (reference only):
enter image description here





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






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.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages