add shapes in MVVM

5 posts, 0 answers
  1. Affreux
    Affreux avatar
    4 posts
    Member since:
    May 2014

    Posted 01 Jun 2016 Link to this post


    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



  2. Petar Mladenov
    Petar Mladenov avatar
    2991 posts

    Posted 06 Jun 2016 Link to this post

    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.
  3. Affreux
    Affreux avatar
    4 posts
    Member since:
    May 2014

    Posted 06 Jun 2016 in reply to Petar Mladenov Link to this post

    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.

  4. Affreux
    Affreux avatar
    4 posts
    Member since:
    May 2014

    Posted 06 Jun 2016 in reply to Petar Mladenov Link to this post

    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)
  5. Petar Mladenov
    Petar Mladenov avatar
    2991 posts

    Posted 07 Jun 2016 Link to this post

    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.
Back to Top