使用wpf向canvas添加形状的最佳方法?

时间:2021-06-27 15:55:05

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?

我需要通过代码将几何对象添加到画布中。当您单击按钮时,意味着添加了一个形状。我将画布作为参数发送到函数,然后使用canvas.children.add(),但这种螺丝整个mvvm的想法,不是吗?有没有更好的方法呢?

2 个解决方案

#1


5  

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.

您可以将ItemsControl与Canvas一起用作项目面板。然后在VM中,您需要一个集合来保存所有项目。每个项目都应具有展示位置的所有属性。

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:

在VM中:

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

In XAML:

在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>

#2


-1  

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.

如果在XAML中定义形状,它们就会以相同的方式将Add()'添加到Canvas.Children中。

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)

现在,如果你想以干净的Mvvm方式做到这一点,你可能必须对你的viewmodel有所创新。我为按钮添加了一个VM ICommand(所以你可以连接它),在处理程序中,我将一些对象添加到ObservableCollection,然后在你的视图中做一些事情来创建ViewModel集合中的形状(在xaml或codebehind中)

#1


5  

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.

您可以将ItemsControl与Canvas一起用作项目面板。然后在VM中,您需要一个集合来保存所有项目。每个项目都应具有展示位置的所有属性。

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:

在VM中:

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

In XAML:

在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>

#2


-1  

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.

如果在XAML中定义形状,它们就会以相同的方式将Add()'添加到Canvas.Children中。

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)

现在,如果你想以干净的Mvvm方式做到这一点,你可能必须对你的viewmodel有所创新。我为按钮添加了一个VM ICommand(所以你可以连接它),在处理程序中,我将一些对象添加到ObservableCollection,然后在你的视图中做一些事情来创建ViewModel集合中的形状(在xaml或codebehind中)