This is a migrated thread and some comments may be shown as answers.

add shapes in MVVM

4 Answers 153 Views
This is a migrated thread and some comments may be shown as answers.
Top achievements
Rank 1
Affreux asked on 01 Jun 2016, 03:44 PM


I'm using a RadDiagram in my application. The GraphSource is backed by a ViewModel.

I need to draw shapes on the diagram, and have them added to the GraphSource. How can I achieve that?


I created a small test project, below. It has a window and a View Model.

At present, when I draw a path, new MyBaseNode object is created, but none of its properties have a value.


01.<Window x:Class="MainWindow"
04.        xmlns:telerik=""
05.        xmlns:primitives="clr-namespace:Telerik.Windows.Controls.Diagrams.Primitives;assembly=Telerik.Windows.Controls.Diagrams"
08.        xmlns:my="clr-namespace:MvvmShapes"
09.        mc:Ignorable="d"
10.        Title="MainWindow"
11.        d:DesignWidth="800"
12.        d:DesignHeight="300"
13.        Height="350"
14.        Width="525">
15.    <Window.DataContext>
16.        <my:MyViewModel />
17.    </Window.DataContext>
18.    <Grid>
19.        <telerik:RadDiagram GraphSource="{Binding Graph, Mode=OneTime}"
20.                            ActiveTool="{Binding DiagramTool}">
21.            <telerik:RadDiagram.ShapeStyle>
22.                <Style TargetType="telerik:RadDiagramShape">
23.                    <!-- ce style relie les propriétés du ViewModel aux propriétés des formes dans le diagramme -->
24.                    <!-- position -->
25.                    <Setter Property="Position"
26.                            Value="{Binding Position, Mode=TwoWay}" />
27.                    <!-- rotation -->
28.                    <Setter Property="RotationAngle"
29.                            Value="{Binding RotationAngle, Mode=TwoWay}" />
30.                    <!-- width and height -->
31.                    <Setter Property="Width"
32.                            Value="{Binding Width, Mode=TwoWay}" />
33.                    <Setter Property="Height"
34.                            Value="{Binding Height, Mode=TwoWay}" />
35.                    <Setter Property="Content"
36.                            Value="{Binding Content, Mode=OneTime}" />
37.                    <Setter Property="Template">
38.                        <Setter.Value>
39.                            <ControlTemplate>
40.                                <TextBlock Text="{Binding Content}" />
41.                            </ControlTemplate>
42.                        </Setter.Value>
43.                    </Setter>
44.                </Style>
45.            </telerik:RadDiagram.ShapeStyle>
46.        </telerik:RadDiagram>
48.        <StackPanel HorizontalAlignment="Left">
49.            <Button Command="{Binding CommandPointer, Mode=OneTime}"
50.                    Content="Pointer" />
51.            <Button Command="{Binding CommandLine, Mode=OneTime}"
52.                    Content="Line" />
53.        </StackPanel>
54.    </Grid>


001.Imports Telerik.Windows.Diagrams
002.Imports Telerik.Windows.Controls.Diagrams.Extensions.ViewModels
005.Public Class MyViewModel
006.    Inherits Telerik.Windows.Controls.ViewModelBase
008.    Public Property Graph As New MyGraphSource()
010.    Private _diagram_tool As Telerik.Windows.Diagrams.Core.MouseTool
011.    Public Property DiagramTool As Telerik.Windows.Diagrams.Core.MouseTool
012.        Get
013.            Return _diagram_tool
014.        End Get
015.        Set(value As Telerik.Windows.Diagrams.Core.MouseTool)
016.            _diagram_tool = value
017.            OnPropertyChanged("DiagramTool")
018.        End Set
019.    End Property
021.    Public ReadOnly Property CommandPointer As ICommand
022.        Get
023.            Return New CommandImpl(Sub() DiagramTool = Core.MouseTool.PointerTool)
024.        End Get
025.    End Property
027.    Public ReadOnly Property CommandLine As ICommand
028.        Get
029.            Return New CommandImpl(Sub() DiagramTool = Core.MouseTool.PathTool)
030.        End Get
031.    End Property
032.End Class
034.Public Class MyGraphSource
035.    Inherits ObservableGraphSourceBase(Of MyBaseNode, MyLink)
037.    Public Sub New()
038.        Dim node1 As New MyBaseNode() With {.Content = "node 1", .Position = New Point(100, 100), .Width = 60, .Height = 30}
039.        Dim node2 As New MyBaseNode() With {.Content = "node 2", .Position = New Point(400, 100), .Width = 60, .Height = 30}
040.        Dim node3 As New MyBaseNode() With {.Content = "node 3", .Position = New Point(100, 200), .Width = 60, .Height = 30}
041.        Dim node4 As New MyBaseNode() With {.Content = "node 4", .Position = New Point(400, 400), .Width = 60, .Height = 30}
043.        Dim link1 As New MyLink(node1, node4) With {.Content = "A"}
044.        Dim link2 As New MyLink(node1, node3) With {.Content = "B"}
045.        Dim link3 As New MyLink(node1, node2) With {.Content = "C"}
046.        Dim link4 As New MyLink(node2, node3) With {.Content = "D"}
048.        AddNode(node1)
049.        AddNode(node2)
050.        AddNode(node3)
051.        AddNode(node4)
053.        AddLink(link1)
054.        AddLink(link2)
055.        AddLink(link3)
056.        AddLink(link4)
057.    End Sub
061.End Class
063.Public Class CommandImpl
064.    Implements ICommand
066.    Private _command_action As Action
067.    Public Sub New(p_action As Action)
068.        _command_action = p_action
069.    End Sub
071.    Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
072.        Return True
073.    End Function
075.    Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements ICommand.CanExecuteChanged
077.    Public Sub Execute(parameter As Object) Implements ICommand.Execute
078.        _command_action()
079.    End Sub
080.End Class
082.Public Class MyBaseNode
083.    Inherits NodeViewModelBase
085.    Public Overrides Function ToString() As String
086.        Return If(Content IsNot Nothing, Content.ToString, "")
087.    End Function
088.End Class
091.Public Class MyLink
092.    Inherits LinkViewModelBase(Of MyBaseNode)
094.    Public Sub New()
095.        MyBase.New()
096.    End Sub
098.    Public Sub New(source As MyBaseNode, target As MyBaseNode)
099.        MyBase.New(source, target)
100.    End Sub
102.    Public Overrides Function ToString() As String
103.        Return If(Content IsNot Nothing, Content.ToString, "")
104.    End Function
105.End Class



4 Answers, 1 is accepted

Sort by
Petar Mladenov
Telerik team
answered on 06 Jun 2016, 09:48 AM
Hello Affreux,

I guess you use Path/Pencil tool to draw a shape in the Diagram. When mouse down is triggered in the Diagram, new ViewModel (in your case MyBaseNode  object is created), however it is also expected that the Shapes's Geometry, Width, Height are not prepared and calculated yet.
Could you please elaborate a bit more on your specific scenario, why do you need these properties in such early stage ? And why do you need Width/ Heights properties stored in ViewModel - this is not typical for MVVM - storing UI properties in the ViewModel.

Petar Mladenov
Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
Top achievements
Rank 1
answered on 06 Jun 2016, 10:08 AM

I'm implementing a drawing application, where the user can draw lines, add common shapes (rectangle, circle, thick arrow, etc), and some custom databound shapes (the user adds a shape, and several times in the future I change its text and backcolor).

I need to persist this drawing between sessions.

Top achievements
Rank 1
answered on 06 Jun 2016, 10:10 AM
I don't need the shapes very early, I'd be happy to have their info on MouseUp, but right now, I get nothing (they stay at width=0, height=0)
Petar Mladenov
Telerik team
answered on 07 Jun 2016, 03:47 PM
Hello Joel,

We can use our CustomSettingsPane SDK Sample and our HowToSerialize DataBound Diagram resources as a base for our discussion. As first step, you need to use SerializableGraphSourceBase.

 In the demo (sdk), when you draw a shape with Path/Pencil Tool , the setter of the Geometry property of the ShapeViewModel class will fire (two way binding kicks in after the AddNode from the GraphSource). In order to Serialize / Deserialize the Geometry of the Shapes. You need to:

-- case A (you drag a shape from he toolbox) The default SerializationService saves the shape from toolbox and on drop shape is deserialized. You need to attach to ItemSerializing event and save the geometry:
SerializationService.Default.ItemSerializing += DefaultSerializationService_ItemSerializing;
private void DefaultSerializationService_ItemSerializing(object sender, SerializationEventArgs<IDiagramItem> e)
            if (e.Entity != null && e.Entity is RadDiagramShape)
                var shape = e.Entity as RadDiagramShape;
                if (shape.Geometry != null)
                    e.SerializationInfo["MyGeometry"] = (e.Entity as RadDiagramShape).Geometry.ToString();
On Drop, Deserialize Node of the GraphSOurce is fired when you can restore the ViewModels's Geometry property.

    -case B: You invoke the Save method / command of the Diagram. Then the Serialize method of the SerializableGraphSource is fired so you can save the geometry of the model into the dictionary:
public override void SerializeNode(ShapeViewModel node, SerializationInfo info)
         info["MyGeometry"] = node.Geometry.ToString();
         base.SerializeNode(node, info);
Later on Load, Deserialize will successfully restore the ViewModel.

On a side note, we encourage you to send us a direct support ticket. This way your 24-hours response time is guaranteed.

Petar Mladenov
Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
Asked by
Top achievements
Rank 1
Answers by
Petar Mladenov
Telerik team
Top achievements
Rank 1
Share this question