How to bind a view model to RadDiagramTextShape with TextTool?

4 posts, 1 answers
  1. Michael
    Michael avatar
    26 posts
    Member since:
    Oct 2014

    Posted 22 Dec 2014 Link to this post

    I have a diagram with multiple types of shapes that are bound to a view-model heirarchy that inherits from NodeViewModelBase similar to the following: 

    public class RainbowViewModel : ObservableGraphSourceBase<ColorViewModel, inkViewModelBase<ColorViewModel>>
    { }
     
    public class ColorViewModel : NodeViewModelBase
    {   
      protected string mLabel;
      public string Label
      {
        get
        {
          return mLabel;
        }
        set
        {
          if (mLabel != value)
          {
            mLabel = value;
            OnPropertyChanged("Label");
          }
        }
      }
    }

    nd there are other view model shapes that derive from ColorViewModel and I used a NodeTemplateSelector and NodeStyleSelector to specify the data templates and style templates of each type of node.  So far so good.  But I also need to allow the user to add text annotations to the diagram.  So the user can set the active tool to the TextTool and they are able to draw text.  But, I need to be able to bind the text items the user adds to a corresponding view model and do two-way binding of the text.  When the active tool is the TextTool, and a user adds a text shape to the diagram, the content of the shape is bound to an instance of a ColorViewModel.  I can set a style template for the text shapes that the user adds, but when I bind the text to the underlying view model, things get borked.

    Here is an example of the data template I have tried (and multiple variations of it):

      <DataTemplate x:Key="annotationTemplate">
      <Grid VerticalAlignment="Stretch"
                  HorizontalAlignment="Stretch">
        <TextBox Text="{Binding Label, Mode=TwoWay}"
               TextWrapping="Wrap"
               AcceptsReturn="True"
               VerticalScrollBarVisibility="Auto"
                 HorizontalScrollBarVisibility="Auto"
                 VerticalAlignment="Stretch"
                 HorizontalAlignment="Stretch" />
      </Grid>
    </DataTemplate>

    and here is the style template:

    <Style x:Key="annotationShapeStyle"
           TargetType="telerik:RadDiagramTextShape">
      <Setter Property="Visibility"
              Value="{Binding Visibility, Mode=TwoWay}" />
      <Setter Property="Position"
              Value="{Binding Position, Mode=TwoWay}" />
      <Setter Property="IsResizingEnabled"
              Value="True" />
      <Setter Property="IsRotationEnabled"
              Value="True" />
      <Setter Property="IsEditable"
              Value="True" />
      <Setter Property="IsConnectorsManipulationEnabled"
              Value="False" />
      <Setter Property="Background"
              Value="LightGray" />
    </Style>

    Both templates are being correctly applied but when the data template is applied, the text is bound to the view model but I cannot change certain properties of the text using the  SettingsPane and I cannot get the text box to act like the default text box of the RadDiagramTextShape.  For example, the text box does not scale with the shape, and the forground color does not change when the SettingsPane is used.

    Can anyone provide any advice on how to bind a view model to a RadDiagramTextShape and allow that shape to be edited using the SettingsPane and to have that shape act as like the default text shape?

    Much thanks in advance,

    Mike
  2. Michael
    Michael avatar
    26 posts
    Member since:
    Oct 2014

    Posted 22 Dec 2014 in reply to Michael Link to this post

    Well,

    I've gotten a little farther and figured out some of the issues in the previous post, but a few remain.

    For the text shape, instead of using the template selector to specify the content template, I just ended up specifying them in the style for the text shape.  More importantly, there is a data template for both edit and non-edit modes:

        <!-- Data Templates -->
     
        <DataTemplate x:Key="annotationTemplate">
          <Grid VerticalAlignment="Stretch"
                      HorizontalAlignment="Stretch">
            <TextBlock Text="{Binding Label, Mode=TwoWay}"
                     TextWrapping="Wrap"
                     VerticalAlignment="Stretch"
                     HorizontalAlignment="Stretch" />
          </Grid>
        </DataTemplate>
        <DataTemplate x:Key="annotationEditTemplate">
          <Grid VerticalAlignment="Stretch"
                HorizontalAlignment="Stretch">
            <TextBox Text="{Binding Label, Mode=TwoWay}"
                     TextWrapping="Wrap"
                     AcceptsReturn="True"
                     VerticalScrollBarVisibility="Auto"
                     HorizontalScrollBarVisibility="Auto"
                     VerticalAlignment="Stretch"
                     HorizontalAlignment="Stretch" />
          </Grid>
        </DataTemplate>
     
    <!-- Style Template -->
        <Style x:Key="annotationShapeStyle"
               TargetType="telerik:RadDiagramTextShape">
          <Setter Property="Visibility"
                  Value="{Binding Visibility, Mode=TwoWay}" />
          <Setter Property="Position"
                  Value="{Binding Position, Mode=TwoWay}" />
          <Setter Property="IsResizingEnabled"
                  Value="True" />
          <Setter Property="IsRotationEnabled"
                  Value="True" />
          <Setter Property="IsEditable"
                  Value="True" />
          <Setter Property="IsConnectorsManipulationEnabled"
                  Value="False" />
          <Setter Property="Background"
                  Value="LightGray" />
          <Setter Property="ContentTemplate"
                  Value="{StaticResource annotationTemplate}" />
          <Setter Property="EditTemplate"
                  Value="{StaticResource annotationEditTemplate}" />
        </Style>

    This produces a text shape (when the active tool is TextTool), that is bound to a view model and the behavior of the text mirrors (mostly) that of the default shape when edited with the SettingsPane.  But, one thing I notice was that in the SettingsPane for the shape, the text field is not being updated with the value bound to the text shape.  Instead, the name of the view model is used.  If I edit this field, it causes exceptions.  How do I update this field (see image) of the SettingsPane with the text to be edited? 

    Thanks again,

    MIke
  3. DevCraft banner
  4. Answer
    Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 24 Dec 2014 Link to this post

    Hi Michael,

    By default, the TextBox in the Text tab of the DiagramSettingsPane is bound to the Content of the Selected Diagram shape / connection. That is why in your scenario you see the name of your ViewModel. You actually see the ToString() result of the ViewModel. You will be able to see the correct label if you introduce the following change:
    public class ColorViewModel : NodeViewModelBase
        {
            public override string ToString()
            {
                return this.Label;
            }
     
            protected string mLabel;
            public string Label

    However, for two-way binding you need a customization of the TextBox in the Style of the SettingsPane.
    Normally, the TextBox is two-way bound to the Content of the selected Diagram Item like so:
    <TextBox AcceptsReturn="True" HorizontalAlignment="Stretch"
                                                   telerik:StyleManager.Theme="{StaticResource Theme}"
                                                   VerticalContentAlignment="Center" HorizontalContentAlignment="Stretch"
                                                   extensions:SettingsPaneView.EditorPropertyName="Content"
                                                   extensions:SettingsPaneView.EditorItemType="Shapes, Connections"
                                                   extensions:SettingsPaneView.EditorValue="{Binding Path=Text, Mode=TwoWay, RelativeSource={RelativeSource Self}}">
    EditorPropertyname marks the property of the Shape and EditorValue marks the property of the TextBox.
    However, in MVVM scenario the Content of the Shapes and the Content of the Connections is some ViewModel, but not string. That is why the Editor PropertyName should be changed to something like:
    extensions:SettingsPaneView.EditorPropertyName="DataContext.Label"

    We have similar sample in our GitHub SDK repository - Diagram CustomSettingsPane.

    Our advice for you is to use no-xaml styles with separate xaml files (the approach is described here) and introduce the mentioned EditorPropertyName change in the SettingsPaneTextControlStyle (check out the customization section here). If you do not use implicit styles you need to get the SettingsPaneTextControl Style with its acommpanying styles , brushes and resources and place them in your MainPage /App  Resources  but this are about 200-300 lines of xaml.

    Going deeper into this requirement , this will make the Content of your TextShapes editable two-way. However, I guess you need the SettingsPane to work over other shapes and connections as well. Therefore, I can suggest you to use Interface or common parent class which will provide name of the ViewModels property you wish to edit. For example you can have EditablePropertyName (provided via abstract class or interface) both in your ColorViewModel, ShapeViewModel, ConnectionViewModel which returns this.Label in ColorViewMol, return this.ConnectionLabel in some ConnectionViewModel etc.


    Regards,
    Petar Mladenov
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  5. Michael
    Michael avatar
    26 posts
    Member since:
    Oct 2014

    Posted 24 Dec 2014 Link to this post

    Petar,

    Thanks for the quick response.  This gives me plenty to work with.

    Mike
Back to Top