user2311652
user2311652

Reputation: 51

best way to add shapes to canvas using wpf?

I need to add geometry objects to a canvas through code.. Meaning when you click a button a shape is added. I sent the canvas as a parameter to the function and then use canvas.children.add() but that kind of screws the whole mvvm idea, doesn't it? Is there a better way to do it?

Upvotes: 2

Views: 3587

Answers (2)

XAMeLi
XAMeLi

Reputation: 6289

You can use ItemsControl with Canvas as it's items panel. Then in VM you need a collection to hold all the items. Each item should have all the properties for placement.

So, in code, it will look like this (I'm omitting change notification for brevity):

The item:

public class CanvasShape : INotifyPropertyChanged
{
    public double Top {get; set;}//TODO: add change notification
    public double Left {get; set;}//TODO: add change notification
    public Geometry PathData {get; set;}//TODO: add change notification
}

In the VM:

public ObservableCollection<CanvasShape> Shapes {get; set;}
.....
//Add some logic to fill the collection

In XAML:

<!--The DataContext here is the VM-->
<ItemsControl ItemsSource="{Binding Shapes}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style>
            <!--These setters will control the position of the shape; the DataContext here is CanvasShape-->
            <Setter Property="Cavas.Top" Value="{Binding Top}"/>
            <Setter Property="Cavas.Left" Value="{Binding Left}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Path Data="{Binding PathData}"
                  .......
                  />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Upvotes: 5

Stephane Delcroix
Stephane Delcroix

Reputation: 16230

No, there's no better way to do it.

If you define shapes in XAML, they get Add()'ed to the Canvas.Children just the same way.

Now, if you want to do that in a clean Mvvm way, you probably have to get inventive with your viewmodel. I'd add a VM ICommand for the button (so you can connect ot it), in the handler, I'd add some kind of object to an ObservableCollection, and then do something in your view to create the shapes from that ViewModel Collection (in xaml or codebehind)

Upvotes: -1

Related Questions