The Situation when I will drop and add a shape. before added shape drawing on the diagram, I want to execute Diagram.Align() method with all shapes.
In Detail, I will drop and add ContainerShape into another ContainerShape.
Another ContainerShape has a child, a shape.
After Dropped and Added, I try to Align ContainerShape's Childrens when Other ContainerShape calls "OnItemsCollectionChanged"
but, if i try to Align with dropped shape. it occurs to Empty Rect Error.
"Empty Rect cannot modify this property"
e.StackTrace " location: System.Windows.Rect.set_X(Double value)\r\n location: Telerik.Windows.Diagrams.Core.GraphController.AlignShape(IShape shape, Point oldPosition, Point alignedPosition, Alignment alignment)\r\n location: Telerik.Windows.Diagrams.Core.GraphController.AlignShapes(Alignment alignment, IEnumerable`1 shapes)\r\n location: CloudRPA.Views.Diagram.DiagramContainerShape.ReArrangedItem(Boolean isAdd)"
5 Answers, 1 is accepted
Hi Seokhyun,
Thank you for the provided information. Still, I am not exactly sure what could be the reason behind this error. In your post, you mentioned that you are using the Align command of the RadDiagram in the OnItemsCollectionChanged event. My assumption from this is that you have custom container shape. In this case, may I ask you to try to isolate this behavior in a standalone project which reproduces this exception? This way I can have a better look at your implementation and debug this error on my side.
I am looking forward to your reply.
Regards,
Dinko
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.
I found the situation!
when dragging and add to containerShape2 in containerShape1.
Error occurs when align containerShape1's children. diagram.Align occur Empty Error.
A sample Attached, that the Diagram has one ContainerShape.
and ListView has two Items. "Shape" and "ContainerShape".
if item drag and drop into the Diagram. always add to each Item in Diagram's ContainerShape.
Diagram's Containershape override OnItemsCollectionChanged Event that align containerShape's children when item changed.
one case, add shape. don't occur error.
other case, add containerShape. do occur Empty Rect error.
i don't know why occur error... the error occur only drop and add containerShape.
i made a project for this sample.
but i can't attach .zip file.........
here's a code.
==== MainWindow.xaml Code =====
<Window x:Class="TelerikTest01.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:primitives="clr-namespace:Telerik.Windows.Controls.Diagrams.Primitives;assembly=Telerik.Windows.Controls.Diagrams"
xmlns:local="clr-namespace:TelerikTest01"
Height="600" Width="800">
<Window.Resources>
<Style x:Name="ShapeStyle" x:Key="ShapeStyle" TargetType="{x:Type telerik:RadDiagramShape}">
<Setter Property="IsResizingEnabled" Value="False"/>
</Style>
<Style x:Key="ContainerStyle" TargetType="{x:Type local:CustomContainerShape}">
<Setter Property="Position" Value="{Binding Position}"/>
</Style>
<local:Selector
x:Key="ShapeStyleSelector"
ShapeStyle ="{StaticResource ShapeStyle}"
ContainerStyle="{StaticResource ContainerStyle}"
/>
</Window.Resources>
<Grid>
<Grid.Resources>
<Style x:Key="diagramSelectionRectangleStyle1" TargetType="Rectangle">
<Setter Property="Stroke" Value="#e6001e" />
<Setter Property="Fill" Value="#1ee6001e" />
</Style>
<Style x:Key="diagramSelectionRectangleStyle2" TargetType="Rectangle">
<Setter Property="Stroke" Value="Red" />
<Setter Property="Fill" Value="#0e0095b3" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="180"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView Name="ItemListView" Grid.Column="0" Height="500"
MouseMove="ItemListView_MouseMove">
<ListViewItem Name="Shape" Content="Shape" telerik:DragDropManager.AllowDrag="True"/>
<ListViewItem Name="ContainerShape" Content="ContainerShape" telerik:DragDropManager.AllowDrag="True"/>
</ListView>
<local:CustomDiagram
x:Name="diagram"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Drop="Diagram_Drop"
GraphSource="{Binding CustomSource}"
ShapeStyleSelector="{StaticResource ShapeStyleSelector}"
SnapX="1"
SnapY="1">
</local:CustomDiagram>
</Grid>
</Window>
==== MainWindow.xaml.cs =======
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.Diagrams;
using Telerik.Windows.Diagrams.Core;
using Telerik.Windows.DragDrop;
using System.Collections.ObjectModel;
using Telerik.Windows.Controls.Diagrams.Extensions.ViewModels;
using System.Collections;
using System.ComponentModel;
using System.Collections.Specialized;
namespace TelerikTest01
{
public class BaseModel
{
double X;
double Y;
public int Index { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public bool IsBreakPoint { get; set; }
public bool IsSelected { get; set; }
public bool Disable { get; set; }
private bool isRunning { get; set; }
public object ParentNode { get; set; }
public Point Position
{
get
{
return new Point(X, Y);
}
set
{
X = value.X;
Y = value.Y;
}
}
public ObservableCollection<ConnectorInfo> Connectors { get; } = new ObservableCollection<ConnectorInfo>();
}
public class BaseGroupModel : BaseModel, IContainerItem
{
ObservableCollection<object> InteralItems = new ObservableCollection<object>();
public double X;
public double Y;
public int ItemCount
{
get
{
return InteralItems.Count;
}
}
public int CaseNumber { get; set; }
public ObservableCollection<ConnectorInfo> Connectors { get; } = new ObservableCollection<ConnectorInfo>();
public BaseGroupModel()
{
}
public virtual IEnumerable Items
{
get { return InteralItems; }
}
public virtual bool AddItem(object item)
{
if (item is BaseModel node)
{
node.ParentNode = this;
InteralItems.Add(node);
}
else if (item is Link link)
{
InteralItems.Add(link);
}
else return false;
return true;
}
public virtual bool RemoveItem(object item)
{
if (item is BaseModel node)
{
node.ParentNode = null;
InteralItems.Remove(node);
}
else if (item is Link link)
{
InteralItems.Add(link);
}
else return false;
return true;
}
}
// Link Style Type
public enum DiagramLinkType
{
Normal,
InnerStart,
CollapseLine,
HiddenLine,
DragOverLine,
DragOverHiddenLine
}
public class Link : ILink<BaseModel>
{
public BaseModel Source { get; set; }
public BaseModel Target { get; set; }
public string SourceConnectorPosition { get; set; }
public string TargetConnectorPosition { get; set; }
public string Name { get; set; }
public DiagramLinkType LinkType { get; set; }
object ILink.Source
{
get => this.Source;
set { }
}
object ILink.Target
{
get => this.Target;
set { }
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// containerShape model test
ObservableGraphSourceBase<BaseModel, Link> graphSource = new ObservableGraphSourceBase<BaseModel, Link>();
BaseGroupModel baseGroup;
public MainWindow()
{
InitializeComponent();
diagram.GraphSource = graphSource;
baseGroup = new BaseGroupModel() { Position = new Point(300, 200) };
graphSource.AddNode(baseGroup);
}
private void ItemListView_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
DataObject data = new DataObject(ItemListView.SelectedItem);
DragDrop.DoDragDrop(ItemListView, data, DragDropEffects.Move);
}
}
private void Diagram_Drop(object sender, System.Windows.DragEventArgs e)
{
Point position = e.GetPosition(diagram);
if(e.Data != null)
{
ListViewItem item = e.Data.GetData("System.Windows.Controls.ListViewItem") as ListViewItem;
if(item != null)
{
if (item.Name.Equals("Shape"))
{
baseGroup.AddItem(new BaseModel() { Position = position });
}
else if (item.Name.Equals("ContainerShape"))
{
baseGroup.AddItem(new BaseGroupModel() { Position = position });
}
}
}
}
}
public class CustomContainerShape : RadDiagramContainerShape
{
CustomDiagram diagram;
public CustomContainerShape(CustomDiagram diagram)
{
this.diagram = diagram;
}
protected override void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
base.OnItemsCollectionChanged(sender, e);
List<IShape> shapes = this.Children.Where(item => item is IShape).Cast<IShape>().ToList();
try
{
diagram.Align(Alignment.Center, shapes);
}
catch(Exception err)
{
Console.WriteLine(err.Message);
}
}
}
public class CustomShape : RadDiagramShape
{
public CustomShape()
{
}
}
public class CustomDiagram: RadDiagram
{
public CustomDiagram()
{
}
protected override bool IsItemItsOwnShapeContainerOverride(object item)
{
bool isCheck = base.IsItemItsOwnShapeContainerOverride(item);
return isCheck;
}
protected override Telerik.Windows.Diagrams.Core.IShape GetShapeContainerForItemOverride(object item)
{
if (item is BaseModel node)
{
return new CustomShape();
}
return base.GetShapeContainerForItemOverride(item);
}
protected override IContainerShape GetShapeContainerForItemOverride(IContainerItem item)
{
return new CustomContainerShape(this);
}
protected override Telerik.Windows.Diagrams.Core.IConnection GetConnectionContainerForItemOverride(object item)
{
return base.GetConnectionContainerForItemOverride(item);
}
}
}
======selector.cs =====
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace TelerikTest01
{
class Selector : StyleSelector
{
public Style ShapeStyle { get; set; }
public Style ContainerStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
if (item is BaseGroupModel)
{
return ContainerStyle;
}
else if(item is BaseModel) return ShapeStyle;
return base.SelectStyle(item, container);
}
}
}
Hello Seokhyun,
Thank you for the provided code snippets.
Let me start with that the RadDiagram control supports data binding through its GraphSource property and the extension view models. With that said, the view model which should be used are:
- ItemViewModelBase - a ViewModel designed to describe a few common properties of the RadDiagramItems.
- NodeViewModelBase - a ViewModel designed to describe a RadDiagramShape.
- LinkViewModelBase - a ViewModel designed to describe a RadDiagramConnection.
- ContainerNodeViewModelBase - a ViewModel designed to describe a RadDiagramContainerShape.
- HierarchicalNodeViewModel - a ViewModel designed to describe a hierarchical RadDiagramShape.
You can check the Use MVVM in the RadDiagram help article, which describes how you can add shapes, containers, and links in the MVVM scenario.
Upon checking the provided code snippet, you have a custom implementation of the view models which could cause such errors to appear, due to missing functionalities which above mentioned classes provide.
What I would suggest here is to check the MVVM for the RadDiagram article, which I think can be used as a base of your application. We also have an SDK example in our GitHub repository based on this article. You can use the SDK as a starting point.
As a side note, you will probably need to populate the RadDiagramToolBox with custom shapes. For this purpose, you can check the CustomToolboxDragDrop SDK example.
I hope this information is helpful.
Regards,
Dinko
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.