Using the MVVM Template in a WPF Application

I am making a simple WPF application with shapes that are drawn on canvas. The view consists of a map , which has a somewhat complex sequence of several squares in different static positions on the map.

MapView is a UserControl that contains a viewbox and canvas. The squares are presented by UserControl with a simple canvas and shape (ellipse in code):

<Canvas> <Canvas.Resources> <BooleanToVisibilityConverter x:Key="boolToVisibility" /> </Canvas.Resources> <Ellipse Stroke="Black" Fill="{Binding Color}" Width="{Binding Dimension}" Height="{Binding Dimension}" /> <Ellipse Stroke="Black" Fill="Black" Canvas.Top="15" Canvas.Left="15" Width="20" Height="20" Visibility="{Binding IsOccupied, Converter={StaticResource boolToVisibility}}" /> </Canvas> 

Obviously, all views have a ViewModel (bound via the DataContext property of the view), backed by a model.

My questions:

  • There is a mousedown event on my map in SquareViews, and each view is a model, I am confused about how to implement this in my application (regarding the MVVM template). Do I have to predefine SquareViews in XAML and then generate models, or pre-create models and dynamically create a view based on the changes made to my model at runtime.

  • How to distinguish SquareViews? Based on (view) links to a model? Position coordinates? I would like not to give a separate name to each individual square ...

  • Another way to set the DataContext view on it is the corresponding viewmodel (without the need to use a framework), instead of adding it to the view code.

  • Is there a better way to position the squares on my map? (I know that the canvas is not very flexible when it comes to scaling, about different resolutions, tags, etc., but presumably the viewbox should improve this, although I have not fully tested it yet)

PS Please let me know if my description / questions are vague / abstract.

+4
source share
3 answers

If I understand your question ....

I think the approach you can take is to use DataTemplates, ItemsControl, and possibly a ContentPresentor.

In fact, you want to say that WPF "displays" your view models. Since your view models are just classes, WPF does not know how to โ€œrenderโ€ them. This is where DataTemplates appear. The bonus of this approach is that the DataContext for the contents of the DataTemplate will be automatically set to the view model. DataTemplates are defined in your Window or UserControl resources:

 <Window.Resources> <DataTemplate DataType="{x:Type ViewModels:SquareViewModel}"> <Views:SquareView /> </DataTemplate> </Window.Resources> 

The above code will display the SquareView control when WPF encounters a SquareViewModel (and set the DataContext to SquareView on SquareViewModel).

To place your view models in a view, you can use ContentPresenter (for one ViewModel):

 <ContentPresenter Content="{Binding SingleSquare}" /> 

In your case, you want a collection of SquareViewModel elements to be displayed, so you want to use ItemsControl:

 <ItemsControl ItemsSource="{Binding Squares}" /> 

This, however, will not give you the desired result, since by default it will act like a ListBox. You will need to apply the template to the ItemsControl to use the main canvas. See this Pete Brown blog for a possible implementation.

Good luck

Edit: additional sample code


Browse Models:

 public class MainViewModel { public IEnumerable<SquareViewModel> Squares { get; set; } public MainViewModel() { var squares = new List<SquareViewModel>(); squares.Add(new SquareViewModel(15, 15,100,100, Brushes.CadetBlue, "Square One")); squares.Add(new SquareViewModel(75,125, 80, 80, Brushes.Indigo, "Square Two")); Squares = squares; } } public class SquareViewModel { public int X { get; set; } public int Y { get; set; } public int Width { get; set; } public int Height { get; set; } public Brush Color { get; set; } public string Name { get; set; } public SquareViewModel(int x, int y, int width, int height, Brush color, string name) { X = x; Y = y; Width = width; Height = height; Color = color; Name = name; } } 

Views

 <UserControl x:Class="MapView.Views.SquareView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <Grid Background="{Binding Color, FallbackValue=Azure}"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Name, FallbackValue=None}" /> </Grid> </UserControl> <Window x:Class="MapView.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewModels="clr-namespace:MapView.ViewModels" xmlns:Views="clr-namespace:MapView.Views" Title="Window1" Height="300" Width="300"> <Window.Resources> <DataTemplate DataType="{x:Type ViewModels:SquareViewModel}"> <Views:SquareView /> </DataTemplate> </Window.Resources> <ItemsControl ItemsSource="{Binding Squares}" > <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Beige" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style TargetType="ContentPresenter"> <Setter Property="Canvas.Left" Value="{Binding X}" /> <Setter Property="Canvas.Top" Value="{Binding Y}" /> <Setter Property="Width" Value="{Binding Width}" /> <Setter Property="Height" Value="{Binding Height}" /> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl> </Window> 

And in the constructor of Window1:

 public partial class Window1 : Window { public Window1() { InitializeComponent(); DataContext = new MainViewModel(); } } 
+3
source

Take a look at this blog by Ryan Cromwell. Basically, you want to display a โ€œlistโ€ of squares on the canvas. He explains how to do exactly what I think you are asking.

+1
source

You need to come up with some kind of grid structure (WPF Datagrid will do for u). The advantage of the grid is that it can be used as rows that can be considered as x coordinates and columns as y coordinates. Before you start the implementation, imagine what exactly you want to display in the user interface. WPF is just a technology to turn your imagination into reality. If your application is controlled by the UI, first collect all the actions that are possible from the user interface, create a command for these actions in the view model.

+1
source

Source: https://habr.com/ru/post/1342921/


All Articles