WPF实现DiagramChart

1、文件架构
在这里插入图片描述
2、FlowChartStencils.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="clr-namespace:DiagramDesigner"xmlns:c="clr-namespace:DiagramDesigner.Controls"><!--Stroke 设置--><Brush x:Key="ItemStroke">#FFD69436</Brush><!--LinearGradientBrush 设置--><LinearGradientBrush x:Key="ItemBrush" StartPoint="0,0" EndPoint="0,1"><LinearGradientBrush.GradientStops><GradientStop Color="#FAFBE9" Offset="0" /><GradientStop Color="Orange" Offset="1" /></LinearGradientBrush.GradientStops></LinearGradientBrush><!--FlowChartItem 设置--><Style x:Key="FlowChartItemStyle" TargetType="Path"><Setter Property="Fill" Value="{StaticResource ItemBrush}"/><Setter Property="Stroke" Value="{StaticResource ItemStroke}"/><Setter Property="StrokeThickness" Value="2"/><Setter Property="StrokeLineJoin" Value="Round"/><Setter Property="Stretch" Value="Fill"/><Setter Property="IsHitTestVisible" Value="False"/><!--SnapsToDevicePixels 此元素的呈现是否应使用特定于设备的像素设置--><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="BitmapEffect"><Setter.Value><DropShadowBitmapEffect Color="#AAA" Direction="315" ShadowDepth="10"Softness="0.5" Opacity="0.6"/></Setter.Value></Setter></Style><!-- Process(矩形) --><Style x:Key="Process" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,0 H 60 V40 H 0 Z"/></Style><!-- Process(矩形属性) --><Style x:Key="Process_DragThumb" TargetType="Path" BasedOn="{StaticResource Process}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Decision(菱形) --><Style x:Key="Decision" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,20 L 30 0 L 60,20 L 30,40 Z"/></Style><!-- Decision(菱形属性) --><Style x:Key="Decision_DragThumb" TargetType="Path" BasedOn="{StaticResource Decision}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Document(文件框) --><Style x:Key="Document" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,0 H 60 V 40 C 30,30 30,50 0,40 Z"/></Style><!-- Document(文件框属性) --><Style x:Key="Document_DragThumb" TargetType="Path" BasedOn="{StaticResource Document}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Data(平行四边形) --><Style x:Key="Data" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 10,0 L 60 0 L 50,40 L 0,40 Z"/></Style><!-- Data(平行四边形属性) --><Style x:Key="Data_DragThumb" TargetType="Path" BasedOn="{StaticResource Data}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Start --><Style x:Key="Start" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 10,20 A 20,20 0 1 1 50,20 A 20,20 0 1 1 10,20"/></Style><Style x:Key="Start_DragThumb" TargetType="Path" BasedOn="{StaticResource Start}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Predefined(带双竖线矩形) --><Style x:Key="Predefined" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 50,0 V 40 M 10,0 V 40 M 0 0 H 60 V 40 H 0 Z"/></Style><Style x:Key="Predefined_DragThumb" TargetType="Path" BasedOn="{StaticResource Predefined}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- StoredData(两边圆弧) --><Style x:Key="StoredData" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 5,0 H 60 A 40,40 0 0 0 60,40 H 5 A 40,40 0 0 1 5,0 Z"/></Style><Style x:Key="StoredData_DragThumb" TargetType="Path" BasedOn="{StaticResource StoredData}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- InternalStorage(十字矩形) --><Style x:Key="InternalStorage" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,10 H 60 M 10,0 V 40 M 0,0 H 60 V 40 H 0 Z"/></Style><Style x:Key="InternalStorage_DragThumb" TargetType="Path" BasedOn="{StaticResource InternalStorage}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- SequentialData --><Style x:Key="SequentialData" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 30,40 A 20,20 0 1 1 30,0 A 20,20 0 0 1 43,35 H 50 L 50,40 Z"/></Style><Style x:Key="SequentialData_DragThumb" TargetType="Path" BasedOn="{StaticResource SequentialData}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- DirectData --><Style x:Key="DirectData" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="F 1 M 57,40 H 3 A 4,20 0 1 1 3,0 H 57 A 4,20.1 0 1 1 56,0"/></Style><Style x:Key="DirectData_DragThumb" TargetType="Path" BasedOn="{StaticResource DirectData}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- ManualInput --><Style x:Key="ManualInput" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0 10 L 60,0 V 40 H 0 Z"/></Style><Style x:Key="ManualInput_DragThumb" TargetType="Path" BasedOn="{StaticResource ManualInput}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Card --><Style x:Key="Card" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0 10 L 10,0 H 60 V 40 H 0 Z"/></Style><Style x:Key="Card_DragThumb" TargetType="Path" BasedOn="{StaticResource Card}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- PaperTape --><Style x:Key="PaperTape" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,3 C 30,-7 30,13 60,3 V 37 C 30,47 30,27 0,37 Z"/></Style><Style x:Key="PaperTape_DragThumb" TargetType="Path" BasedOn="{StaticResource PaperTape}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Delay --><Style x:Key="Delay" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,0 H 40 A 20,20 0 0 1 40,40 H 0 Z"/></Style><Style x:Key="Delay_DragThumb" TargetType="Path" BasedOn="{StaticResource Delay}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Terminator --><Style x:Key="Terminator" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 20,40 A 20,20 0 0 1 20,0 H 40 A 20,20 0 0 1 40,40 Z"/></Style><Style x:Key="Terminator_DragThumb" TargetType="Path" BasedOn="{StaticResource Terminator}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Display --><Style x:Key="Display" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,20 A 40,40 0 0 1 15,0 H 55 A 60,60 0 0 1 55,40 H 15 A 40,40, 0 0 1 0,20 Z"/></Style><Style x:Key="Display_DragThumb" TargetType="Path" BasedOn="{StaticResource Display}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- LoopLimit --><Style x:Key="LoopLimit" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0 10 L 10,0 H 50 L 60,10 V 40 H 0 Z"/></Style><Style x:Key="LoopLimit_DragThumb" TargetType="Path" BasedOn="{StaticResource LoopLimit}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Preparation --><Style x:Key="Preparation" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0,20 L 10,0  H 50 L 60,20 L 50,40 H10 Z"/></Style><Style x:Key="Preparation_DragThumb" TargetType="Path" BasedOn="{StaticResource Preparation}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- ManualOperation --><Style x:Key="ManualOperation" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0 0 H 60 L 50 40 H 10 Z"/></Style><Style x:Key="ManualOperation_DragThumb" TargetType="Path" BasedOn="{StaticResource ManualOperation}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- OffPageReference --><Style x:Key="OffPageReference" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 0 0 H 60 V 20 L 30,40 L 0,20 Z"/></Style><Style x:Key="OffPageReference_DragThumb" TargetType="Path" BasedOn="{StaticResource OffPageReference}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><!-- Star --><Style x:Key="Star" TargetType="Path" BasedOn="{StaticResource FlowChartItemStyle}"><Setter Property="Data" Value="M 9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7 Z"/></Style><Style x:Key="Star_DragThumb" TargetType="Path" BasedOn="{StaticResource Star}"><Setter Property="IsHitTestVisible" Value="true"/><Setter Property="Fill" Value="Transparent"/><Setter Property="Stroke" Value="Transparent"/></Style><s:Toolbox x:Key="FlowChartStencils" ItemSize="60,50" SnapsToDevicePixels="True"ScrollViewer.HorizontalScrollBarVisibility="Disabled"><ItemsControl.Items><Path Style="{StaticResource Process}" ToolTip="Process"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Process_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource Decision}" ToolTip="Decision"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Decision_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource Document}" ToolTip="Document"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Document_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate><s:DesignerItem.ConnectorDecoratorTemplate><ControlTemplate><c:RelativePositionPanel Margin="-4"><s:Connector Orientation="Top" c:RelativePositionPanel.RelativePosition="0.5,0"/><s:Connector Orientation="Left" c:RelativePositionPanel.RelativePosition="0,0.5"/><s:Connector Orientation="Right" c:RelativePositionPanel.RelativePosition="1,0.5"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.5,0.93"/></c:RelativePositionPanel></ControlTemplate></s:DesignerItem.ConnectorDecoratorTemplate></Path><Path Style="{StaticResource Data}" ToolTip="Data"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Data_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate><s:DesignerItem.ConnectorDecoratorTemplate><ControlTemplate><c:RelativePositionPanel Margin="-4"><s:Connector Orientation="Top" c:RelativePositionPanel.RelativePosition="0.5,0"/><s:Connector Orientation="Left" c:RelativePositionPanel.RelativePosition="0.09,0.5"/><s:Connector Orientation="Right" c:RelativePositionPanel.RelativePosition="0.91,0.5"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.5,1"/></c:RelativePositionPanel></ControlTemplate></s:DesignerItem.ConnectorDecoratorTemplate></Path><Path Style="{StaticResource Start}" ToolTip="Start"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Start_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource PaperTape}" ToolTip="Paper Tape"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource PaperTape_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate><s:DesignerItem.ConnectorDecoratorTemplate><ControlTemplate><c:RelativePositionPanel Margin="-4"><s:Connector Orientation="Top" c:RelativePositionPanel.RelativePosition="0.5,0.07"/><s:Connector Orientation="Left" c:RelativePositionPanel.RelativePosition="0,0.5"/><s:Connector Orientation="Right" c:RelativePositionPanel.RelativePosition="1,0.5"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.5,0.93"/></c:RelativePositionPanel></ControlTemplate></s:DesignerItem.ConnectorDecoratorTemplate></Path><Path Style="{StaticResource Predefined}" ToolTip="Predefined"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Predefined_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource StoredData}" ToolTip="Stored Data"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource StoredData_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate><s:DesignerItem.ConnectorDecoratorTemplate><ControlTemplate><c:RelativePositionPanel Margin="-4"><s:Connector Orientation="Top" c:RelativePositionPanel.RelativePosition="0.5,0"/><s:Connector Orientation="Left" c:RelativePositionPanel.RelativePosition="0,0.5"/><s:Connector Orientation="Right" c:RelativePositionPanel.RelativePosition="0.9,0.5"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.5,1"/></c:RelativePositionPanel></ControlTemplate></s:DesignerItem.ConnectorDecoratorTemplate></Path><Path Style="{StaticResource InternalStorage}" ToolTip="Internal Storage"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource InternalStorage_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource SequentialData}" ToolTip="Sequential Data"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource SequentialData_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource DirectData}" ToolTip="Direct Data"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource DirectData_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource ManualInput}" ToolTip="Manual Input"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource ManualInput_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate><s:DesignerItem.ConnectorDecoratorTemplate><ControlTemplate><c:RelativePositionPanel Margin="-4"><s:Connector Orientation="Top" c:RelativePositionPanel.RelativePosition="0.5,0.12"/><s:Connector Orientation="Left" c:RelativePositionPanel.RelativePosition="0,0.5"/><s:Connector Orientation="Right" c:RelativePositionPanel.RelativePosition="1,0.5"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.5,1"/></c:RelativePositionPanel></ControlTemplate></s:DesignerItem.ConnectorDecoratorTemplate></Path><Path Style="{StaticResource Card}" ToolTip="Card"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Card_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource Delay}" ToolTip="Delay"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Delay_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource Terminator}" ToolTip="Terminator"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Terminator_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource Display}" ToolTip="Display"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Display_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource LoopLimit}" ToolTip="Loop Limit"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource LoopLimit_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource Preparation}" ToolTip="Preparation"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource Preparation_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path><Path Style="{StaticResource ManualOperation}" ToolTip="Manual Operation"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource ManualOperation_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate><s:DesignerItem.ConnectorDecoratorTemplate><ControlTemplate><c:RelativePositionPanel Margin="-4"><s:Connector Orientation="Top" c:RelativePositionPanel.RelativePosition="0.5,0"/><s:Connector Orientation="Left" c:RelativePositionPanel.RelativePosition="0.1,0.5"/><s:Connector Orientation="Right" c:RelativePositionPanel.RelativePosition="0.9,0.5"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.5,1"/></c:RelativePositionPanel></ControlTemplate></s:DesignerItem.ConnectorDecoratorTemplate></Path><Path Style="{StaticResource OffPageReference}" ToolTip="Off Page Reference"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Style="{StaticResource OffPageReference_DragThumb}"/></ControlTemplate></s:DesignerItem.DragThumbTemplate></Path></ItemsControl.Items></s:Toolbox>
</ResourceDictionary>

3、ShapeStencils.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="clr-namespace:DiagramDesigner"xmlns:c="clr-namespace:DiagramDesigner.Controls"><RadialGradientBrush x:Key="RadialBrushOrange" Center="0.2, 0.2" GradientOrigin="0.2, 0.2" RadiusX="0.8" RadiusY="0.8"><GradientStop Color="White" Offset="0"/><GradientStop Color="Orange" Offset="0.9"/></RadialGradientBrush><RadialGradientBrush x:Key="RadialBrushGreen" Center="0.2, 0.2" GradientOrigin="0.2, 0.2" RadiusX="0.8" RadiusY="0.8"><GradientStop Color="White" Offset="0"/><GradientStop Color="Green" Offset="0.9"/></RadialGradientBrush><RadialGradientBrush x:Key="RadialBrushBlue" Center="0.2, 0.2" GradientOrigin="0.2, 0.2" RadiusX="0.8" RadiusY="0.8"><GradientStop Color="White" Offset="0"/><GradientStop Color="Blue" Offset="0.9"/></RadialGradientBrush><LinearGradientBrush x:Key="Brush6" StartPoint="0,0" EndPoint="0,1" Opacity="1"><LinearGradientBrush.GradientStops><GradientStop Color="#FAFBE9" Offset="0.1" /><GradientStop Color="Orange" Offset="1" /></LinearGradientBrush.GradientStops></LinearGradientBrush><s:Toolbox x:Key="ShapeStencils" ItemSize="60,60"><ItemsControl.Items><Ellipse Fill="{StaticResource RadialBrushOrange}" ToolTip="Ellipse" IsHitTestVisible="false"><Ellipse.BitmapEffect><DropShadowBitmapEffect Color="Gray" Direction="315" ShadowDepth="15" Softness="0.8" Opacity="0.4"/></Ellipse.BitmapEffect></Ellipse><Ellipse Fill="{StaticResource RadialBrushBlue}" ToolTip="Ellipse" IsHitTestVisible="false"><Ellipse.BitmapEffect><DropShadowBitmapEffect Color="Gray" Direction="315" ShadowDepth="15" Softness="0.8" Opacity="0.4"/></Ellipse.BitmapEffect></Ellipse><Ellipse Fill="{StaticResource RadialBrushGreen}" ToolTip="Ellipse" IsHitTestVisible="false"><Ellipse.BitmapEffect><DropShadowBitmapEffect Color="Gray" Direction="315" ShadowDepth="15" Softness="0.8" Opacity="0.4"/></Ellipse.BitmapEffect></Ellipse><Path Stretch="Fill" IsHitTestVisible="false"StrokeLineJoin="Round"Fill="{StaticResource Brush6}"Stroke="#AAFF8C00"StrokeThickness="3"Data="M 9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7 Z"><s:DesignerItem.DragThumbTemplate><ControlTemplate><Path Fill="Transparent" Stretch="Fill" Data="M 9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7 Z"/></ControlTemplate></s:DesignerItem.DragThumbTemplate><s:DesignerItem.ConnectorDecoratorTemplate><ControlTemplate><c:RelativePositionPanel Margin="-4"><s:Connector Orientation="Top" c:RelativePositionPanel.RelativePosition="0.5,0"/><s:Connector Orientation="Left" c:RelativePositionPanel.RelativePosition="0,0.385"/><s:Connector Orientation="Right" c:RelativePositionPanel.RelativePosition="1,0.385"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.185,1"/><s:Connector Orientation="Bottom" c:RelativePositionPanel.RelativePosition="0.815,1"/></c:RelativePositionPanel></ControlTemplate></s:DesignerItem.ConnectorDecoratorTemplate></Path></ItemsControl.Items></s:Toolbox>
</ResourceDictionary>

4、SymbolStencils.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="clr-namespace:DiagramDesigner"xmlns:c="clr-namespace:DiagramDesigner.Controls"><s:Toolbox x:Key="SymbolStencils" ItemSize="60,60"><ItemsControl.Items><!--设置IsHitTestVisble属性值为false,可以使界面元素不响应鼠标,鼠标事件也不会被触发--><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/attention.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/info.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/arrow.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/plus.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/chart3.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/printer.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/hexagon.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/chart1.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/chart2.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/world.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/software.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/walk.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/nuclear.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/ring.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/mail.png"/><Image IsHitTestVisible="False" Stretch="Fill" Source="../Images/cross.png"/></ItemsControl.Items></s:Toolbox>
</ResourceDictionary>

5、Expander.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Shared.xaml" /></ResourceDictionary.MergedDictionaries><!-- SimpleStyles: Expander(设计风格) --><ControlTemplate x:Key="ExpanderToggleButton" TargetType="ToggleButton"><BorderName="Border" CornerRadius="2,0,0,0"Background="Transparent"BorderBrush="{StaticResource NormalBorderBrush}"BorderThickness="0,0,0,0"><Path Name="Arrow"Fill="{StaticResource GlyphBrush}"HorizontalAlignment="Center"VerticalAlignment="Center"Data="M 0 0 L 4 4 L 8 0 Z"/></Border><ControlTemplate.Triggers><Trigger Property="ToggleButton.IsMouseOver" Value="true"><Setter TargetName="Border" Property="Background"Value="{StaticResource DarkBrush}" /></Trigger><Trigger Property="IsPressed" Value="true"><Setter TargetName="Border" Property="Background"Value="{StaticResource PressedBrush}" /></Trigger><Trigger Property="IsChecked" Value="true"><Setter TargetName="Arrow" Property="Data"Value="M 0 4 L 4 0 L 8 4 Z" /></Trigger><Trigger Property="IsEnabled" Value="False"><Setter TargetName="Border" Property="Background"Value="{StaticResource DisabledBackgroundBrush}" /><Setter TargetName="Border" Property="BorderBrush"Value="{StaticResource DisabledBorderBrush}" /><Setter Property="Foreground"Value="{StaticResource DisabledForegroundBrush}"/><Setter TargetName="Arrow" Property="Fill"Value="{StaticResource DisabledForegroundBrush}" /></Trigger></ControlTemplate.Triggers></ControlTemplate><Style TargetType="Expander"><Setter Property="FontFamily" Value="SegoeUI"/><Setter Property="FontSize" Value="12"/><Setter Property="Foreground" Value="#4C4C4C"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Expander"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Name="ContentRow" Height="0"/></Grid.RowDefinitions><Border Name="Border" Grid.Row="0" Background="{StaticResource LightBrush}"BorderBrush="{StaticResource NormalBorderBrush}"BorderThickness="1" CornerRadius="2,2,0,0" ><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="20" /><ColumnDefinition Width="*" /></Grid.ColumnDefinitions><ToggleButtonIsChecked="{Binding Path=IsExpanded,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"OverridesDefaultStyle="True" Template="{StaticResource ExpanderToggleButton}" Background="{StaticResource NormalBrush}" /><ContentPresenter Grid.Column="1"Margin="4" ContentSource="Header" RecognizesAccessKey="True" /></Grid></Border><Border Name="Content" Grid.Row="1" Background="{StaticResource WindowBackgroundBrush}"BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="1,0,1,1" CornerRadius="0,0,2,2" ><ContentPresenter Margin="4" /></Border></Grid><ControlTemplate.Triggers><Trigger Property="IsExpanded" Value="True"><Setter TargetName="ContentRow" Property="Height"Value="{Binding ElementName=Content,Path=DesiredHeight}" /></Trigger><Trigger Property="IsEnabled" Value="False"><Setter TargetName="Border" Property="Background"Value="{StaticResource DisabledBackgroundBrush}" /><Setter TargetName="Border" Property="BorderBrush"Value="{StaticResource DisabledBorderBrush}" /><Setter Property="Foreground"Value="{StaticResource DisabledForegroundBrush}"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

6、GroupBox.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Shared.xaml" /></ResourceDictionary.MergedDictionaries><!-- SimpleStyles: GroupBox(设计风格) --><Style TargetType="GroupBox"><Setter Property="FontFamily" Value="SegoeUI"/><Setter Property="FontSize" Value="12"/><Setter Property="Foreground" Value="#4C4C4C"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="GroupBox"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><Border Grid.Row="0" Background="{StaticResource LightBrush}"BorderBrush="{StaticResource NormalBorderBrush}"BorderThickness="1" CornerRadius="2,2,0,0" ><ContentPresenter Margin="4" ContentSource="Header" RecognizesAccessKey="True" /></Border><Border Grid.Row="1" Background="{TemplateBinding Background}"BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="1,0,1,1" CornerRadius="0,0,2,2" ><ContentPresenter Margin="4" /></Border></Grid></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

7、ScrollBar.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><!--ScrollBarLineButton风格设计--><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Shared.xaml" /></ResourceDictionary.MergedDictionaries><Style x:Key="ScrollBarLineButton" TargetType="{x:Type RepeatButton}"><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="OverridesDefaultStyle" Value="true"/><Setter Property="Focusable" Value="false"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type RepeatButton}"><Border Name="Border"Margin="1" CornerRadius="2" Background="{StaticResource NormalBrush}"BorderBrush="{StaticResource NormalBorderBrush}"BorderThickness="1"><Path HorizontalAlignment="Center"VerticalAlignment="Center"Fill="{StaticResource GlyphBrush}"Data="{Binding Path=Content,RelativeSource={RelativeSource TemplatedParent}}" /></Border><ControlTemplate.Triggers><Trigger Property="IsPressed" Value="true"><Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" /></Trigger><Trigger Property="IsEnabled" Value="false"><Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style><Style x:Key="ScrollBarPageButton" TargetType="{x:Type RepeatButton}"><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="OverridesDefaultStyle" Value="true"/><Setter Property="IsTabStop" Value="false"/><Setter Property="Focusable" Value="false"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type RepeatButton}"><Border Background="Transparent" /></ControlTemplate></Setter.Value></Setter></Style><Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}"><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="OverridesDefaultStyle" Value="true"/><Setter Property="IsTabStop" Value="false"/><Setter Property="Focusable" Value="false"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Thumb}"><Border CornerRadius="2" Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="1" /></ControlTemplate></Setter.Value></Setter></Style><ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}"><Grid ><Grid.RowDefinitions><RowDefinition MaxHeight="18"/><RowDefinition Height="0.00001*"/><RowDefinition MaxHeight="18"/></Grid.RowDefinitions><BorderGrid.RowSpan="3"CornerRadius="2" Background="#F0F0F0" /><RepeatButton Grid.Row="0"                           Style="{StaticResource ScrollBarLineButton}"Height="18"Command="ScrollBar.LineUpCommand"Content="M 0 4 L 8 4 L 4 0 Z" /><Track Name="PART_Track"Grid.Row="1"IsDirectionReversed="true"><Track.DecreaseRepeatButton><RepeatButton Style="{StaticResource ScrollBarPageButton}"Command="ScrollBar.PageUpCommand" /></Track.DecreaseRepeatButton><Track.Thumb><Thumb Style="{StaticResource ScrollBarThumb}" Margin="1,0,1,0"  Background="{StaticResource HorizontalNormalBrush}"BorderBrush="{StaticResource HorizontalNormalBorderBrush}" /></Track.Thumb><Track.IncreaseRepeatButton><RepeatButton Style="{StaticResource ScrollBarPageButton}"Command="ScrollBar.PageDownCommand" /></Track.IncreaseRepeatButton></Track><RepeatButton Grid.Row="3" Style="{StaticResource ScrollBarLineButton}"Height="18"Command="ScrollBar.LineDownCommand"Content="M 0 0 L 4 4 L 8 0 Z"/></Grid></ControlTemplate><ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type ScrollBar}"><Grid ><Grid.ColumnDefinitions><ColumnDefinition MaxWidth="18"/><ColumnDefinition Width="0.00001*"/><ColumnDefinition MaxWidth="18"/></Grid.ColumnDefinitions><BorderGrid.ColumnSpan="3"CornerRadius="2" Background="#F0F0F0" /><RepeatButton Grid.Column="0"                           Style="{StaticResource ScrollBarLineButton}"Width="18"Command="ScrollBar.LineLeftCommand"Content="M 4 0 L 4 8 L 0 4 Z" /><Track Name="PART_Track"Grid.Column="1"IsDirectionReversed="False"><Track.DecreaseRepeatButton><RepeatButton Style="{StaticResource ScrollBarPageButton}"Command="ScrollBar.PageLeftCommand" /></Track.DecreaseRepeatButton><Track.Thumb><Thumb Style="{StaticResource ScrollBarThumb}" Margin="0,1,0,1"  Background="{StaticResource NormalBrush}"BorderBrush="{StaticResource NormalBorderBrush}" /></Track.Thumb><Track.IncreaseRepeatButton><RepeatButton Style="{StaticResource ScrollBarPageButton}"Command="ScrollBar.PageRightCommand" /></Track.IncreaseRepeatButton></Track><RepeatButton Grid.Column="3" Style="{StaticResource ScrollBarLineButton}"Width="18"Command="ScrollBar.LineRightCommand"Content="M 0 0 L 4 4 L 0 8 Z"/></Grid></ControlTemplate><Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}"><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="OverridesDefaultStyle" Value="true"/><Style.Triggers><Trigger Property="Orientation" Value="Horizontal"><Setter Property="Width" Value="Auto"/><Setter Property="Height" Value="18" /><Setter Property="Template" Value="{StaticResource HorizontalScrollBar}" /></Trigger><Trigger Property="Orientation" Value="Vertical"><Setter Property="Width" Value="18"/><Setter Property="Height" Value="Auto" /><Setter Property="Template" Value="{StaticResource VerticalScrollBar}" /></Trigger></Style.Triggers></Style>
</ResourceDictionary>

8、ScrollViewer.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><!-- SimpleStyles: ScrollViewer风格设计(?) --><Style x:Key="LeftScrollViewer" TargetType="{x:Type ScrollViewer}"><Setter Property="OverridesDefaultStyle" Value="True"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type ScrollViewer}"><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition/><RowDefinition Height="Auto"/></Grid.RowDefinitions><ScrollContentPresenter Grid.Column="1"/><ScrollBar Name="PART_VerticalScrollBar"Value="{TemplateBinding VerticalOffset}"Maximum="{TemplateBinding ScrollableHeight}"ViewportSize="{TemplateBinding ViewportHeight}"Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/><ScrollBar Name="PART_HorizontalScrollBar"Orientation="Horizontal"Grid.Row="1"Grid.Column="1"Value="{TemplateBinding HorizontalOffset}"Maximum="{TemplateBinding ScrollableWidth}"ViewportSize="{TemplateBinding ViewportWidth}"Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/></Grid></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

9、Shared.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><!-- Fill Brushes(画刷定义) --><LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#FFF" Offset="0.0"/><GradientStop Color="#CCC" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#FFF" Offset="0.0"/><GradientStop Color="#CCC" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#FFF" Offset="0.0"/><GradientStop Color="#EEE" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#FFF" Offset="0.0"/><GradientStop Color="#EEE" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#FFF" Offset="0.0"/><GradientStop Color="#AAA" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#BBB" Offset="0.0"/><GradientStop Color="#EEE" Offset="0.1"/><GradientStop Color="#EEE" Offset="0.9"/><GradientStop Color="#FFF" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" /><SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" /><SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" /><SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" /><!-- Border Brushes --><LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#CCC" Offset="0.0"/><GradientStop Color="#444" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#CCC" Offset="0.0"/><GradientStop Color="#444" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#777" Offset="0.0"/><GradientStop Color="#000" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1"><GradientBrush.GradientStops><GradientStopCollection><GradientStop Color="#444" Offset="0.0"/><GradientStop Color="#888" Offset="1.0"/></GradientStopCollection></GradientBrush.GradientStops></LinearGradientBrush><SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" /><SolidColorBrush x:Key="SolidBorderBrush" Color="#888" /><SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" /><SolidColorBrush x:Key="GlyphBrush" Color="#444" /><SolidColorBrush x:Key="LightColorBrush" Color="#DDD" /></ResourceDictionary>

10、ToolTip.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Shared.xaml" /></ResourceDictionary.MergedDictionaries><!-- SimpleStyles: ToolTip(风格设计) --><Style x:Key="{x:Type ToolTip}" TargetType="ToolTip"><Setter Property="OverridesDefaultStyle" Value="true"/><Setter Property="HasDropShadow" Value="True"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="ToolTip"><Border Name="Border"Background="{StaticResource LightBrush}"BorderBrush="{StaticResource SolidBorderBrush}"BorderThickness="1"Width="{TemplateBinding Width}"Height="{TemplateBinding Height}"><ContentPresenterMargin="4" HorizontalAlignment="Left"VerticalAlignment="Top" /></Border><ControlTemplate.Triggers><Trigger Property="HasDropShadow" Value="true"><Setter TargetName="Border" Property="CornerRadius" Value="4"/><Setter TargetName="Border" Property="SnapsToDevicePixels" Value="true"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

11、Connection.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="clr-namespace:DiagramDesigner"xmlns:c="clr-namespace:DiagramDesigner.Controls"><Style TargetType="{x:Type s:Connection}"><Style.Resources><!-- Style for the ConnectorAdorner thumbs --><Style x:Key="ConnectionAdornerThumbStyle" TargetType="{x:Type Thumb}"><Setter Property="Width" Value="12"/><Setter Property="Height" Value="12"/><Setter Property="SnapsToDevicePixels" Value="true"/><Setter Property="RenderTransform"><Setter.Value><TranslateTransform X="-6" Y="-6"/></Setter.Value></Setter><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Thumb}"><Rectangle Fill="#AADCDCDC" Stroke="DodgerBlue" StrokeThickness="1" RadiusX="0" RadiusY="0"/></ControlTemplate></Setter.Value></Setter></Style><!-- Arrow Grid Style --><Style x:Key="ArrowGridStyle" TargetType="Grid"><Setter Property="Width" Value="10"/><Setter Property="Height" Value="10"/><Setter Property="RenderTransform"><Setter.Value><TranslateTransform X="-5" Y="-5"/></Setter.Value></Setter></Style><!-- base style for all arrow shapes --><Style x:Key="ArrowSymbolBaseStyle" TargetType="Path"><Setter Property="Fill" Value="{StaticResource SolidBorderBrush}"/><Setter Property="Stretch" Value="Fill"/></Style><!-- Arrow --><Style x:Key="Arrow" TargetType="Path" BasedOn="{StaticResource ArrowSymbolBaseStyle}"><Setter Property="Data" Value="M0,0 8,4 0,8 Z"/></Style><!-- Diamond  --><Style x:Key="Diamond" TargetType="Path" BasedOn="{StaticResource ArrowSymbolBaseStyle}"><Setter Property="Data" Value="M-5,0 0,-5 5,0 0,5 Z"/></Style></Style.Resources><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type s:Connection}"><Canvas DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" ><Path Name="PART_ConnectionPath"StrokeThickness="2"Stroke="{StaticResource SolidBorderBrush}"StrokeStartLineCap="Round"StrokeEndLineCap="Round"StrokeLineJoin="Round"StrokeDashArray="{Binding StrokeDashArray}"SnapsToDevicePixels="True"Data="{Binding PathGeometry}"></Path><Grid Style="{StaticResource ArrowGridStyle}"Canvas.Left="{Binding AnchorPositionSource.X}"Canvas.Top="{Binding AnchorPositionSource.Y}"><Path Name="PART_SourceAnchorPath"/><Grid.LayoutTransform><RotateTransform Angle="{Binding AnchorAngleSource}"/></Grid.LayoutTransform></Grid><Grid Style="{StaticResource ArrowGridStyle}"Canvas.Left="{Binding AnchorPositionSink.X}"Canvas.Top="{Binding AnchorPositionSink.Y}"><Path Name="PART_SinkAnchorPath"/><Grid.LayoutTransform><RotateTransform Angle="{Binding AnchorAngleSink}"/></Grid.LayoutTransform></Grid><!--Uncomment this to show default label text--><!--<TextBlock Width="100" Height="35" Text="Label"                       Canvas.Left="{Binding LabelPosition.X}"Canvas.Top="{Binding LabelPosition.Y}"><TextBlock.RenderTransform><TranslateTransform X="5" Y="5"/></TextBlock.RenderTransform></TextBlock>--><Canvas.BitmapEffect><DropShadowBitmapEffect Color="Gray" Direction="315" ShadowDepth="10" Softness="0" Opacity="0.1"/></Canvas.BitmapEffect></Canvas><ControlTemplate.Triggers><DataTrigger Value="Arrow" Binding="{Binding RelativeSource={RelativeSource Self},Path=SourceArrowSymbol}"><Setter TargetName="PART_SourceAnchorPath" Property="Style" Value="{StaticResource Arrow}"/></DataTrigger><DataTrigger Value="Diamond" Binding="{Binding RelativeSource={RelativeSource Self},Path=SourceArrowSymbol}"><Setter TargetName="PART_SourceAnchorPath" Property="Style" Value="{StaticResource Diamond}"/></DataTrigger><DataTrigger Value="Arrow" Binding="{Binding RelativeSource={RelativeSource Self},Path=SinkArrowSymbol}"><Setter TargetName="PART_SinkAnchorPath" Property="Style" Value="{StaticResource Arrow}"/></DataTrigger><DataTrigger Value="Diamond" Binding="{Binding RelativeSource={RelativeSource Self},Path=SinkArrowSymbol}"><Setter TargetName="PART_SinkAnchorPath" Property="Style" Value="{StaticResource Diamond}"/></DataTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

12、DesignerItem.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="clr-namespace:DiagramDesigner"xmlns:c="clr-namespace:DiagramDesigner.Controls"><!-- Connector Style --><Style TargetType="{x:Type s:Connector}"><Setter Property="Width" Value="8"/><Setter Property="Height" Value="8"/><Setter Property="Cursor" Value="Cross"/><Setter Property="SnapsToDevicePixels" Value="true"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type s:Connector}"><Grid><!-- transparent extra space makes connector easier to hit --><Rectangle Fill="Transparent" Margin="-2"/><Rectangle Fill="Lavender" StrokeThickness="1" Stroke="#AA000080"/></Grid></ControlTemplate></Setter.Value></Setter></Style><!-- ConnectorDecoratorTemplate Default Template --><ControlTemplate x:Key="ConnectorDecoratorTemplate" TargetType="{x:Type Control}"><Grid Margin="-5"><s:Connector Orientation="Left" VerticalAlignment="Center" HorizontalAlignment="Left"/><s:Connector Orientation="Top" VerticalAlignment="Top" HorizontalAlignment="Center"/><s:Connector Orientation="Right" VerticalAlignment="Center" HorizontalAlignment="Right"/><s:Connector Orientation="Bottom" VerticalAlignment="Bottom" HorizontalAlignment="Center"/></Grid></ControlTemplate><!-- ResizeDecorator Default Template --><ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}"><Grid Opacity="0.7" SnapsToDevicePixels="true"><c:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 -4 0 0"VerticalAlignment="Top" HorizontalAlignment="Stretch"/><c:ResizeThumb Width="3" Cursor="SizeWE" Margin="-4 0 0 0"VerticalAlignment="Stretch" HorizontalAlignment="Left"/><c:ResizeThumb Width="3" Cursor="SizeWE" Margin="0 0 -4 0"VerticalAlignment="Stretch" HorizontalAlignment="Right"/><c:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 0 0 -4"VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/><c:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0"VerticalAlignment="Top" HorizontalAlignment="Left"/><c:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0"VerticalAlignment="Top" HorizontalAlignment="Right"/><c:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6"VerticalAlignment="Bottom" HorizontalAlignment="Left"/><c:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6"VerticalAlignment="Bottom" HorizontalAlignment="Right"/></Grid></ControlTemplate><!-- DragThumb Default Template --><Style TargetType="{x:Type c:DragThumb}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type c:DragThumb}"><Rectangle Fill="Transparent"/></ControlTemplate></Setter.Value></Setter></Style><!-- DesignerItem Style --><Style TargetType="{x:Type s:DesignerItem}"><Setter Property="MinWidth" Value="25"/><Setter Property="MinHeight" Value="25"/><Setter Property="SnapsToDevicePixels" Value="True"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type s:DesignerItem}"><Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"><!-- PART_DragThumb --><c:DragThumb x:Name="PART_DragThumb" Cursor="SizeAll"/><!-- PART_ResizeDecorator --><Control x:Name="PART_ResizeDecorator"Visibility="Collapsed"Template="{StaticResource ResizeDecoratorTemplate}"/><!-- PART_ContentPresenter --><ContentPresenter x:Name="PART_ContentPresenter"HorizontalAlignment="Stretch"VerticalAlignment="Stretch"Content="{TemplateBinding ContentControl.Content}"Margin="{TemplateBinding ContentControl.Padding}"/><!-- PART_ConnectorDecorator --><Control x:Name="PART_ConnectorDecorator"Visibility="Hidden"Template="{StaticResource ConnectorDecoratorTemplate}"/></Grid><ControlTemplate.Triggers><DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self},Path=IsSelected}"><Setter TargetName="PART_ResizeDecorator" Property="Visibility" Value="Visible"/></DataTrigger><Trigger Property="IsMouseOver" Value="true"><Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible"/></Trigger><DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self},Path=IsDragConnectionOver}"><Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible"/></DataTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style></ResourceDictionary>

13、Toolbox.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="clr-namespace:DiagramDesigner"><Style TargetType="{x:Type s:Toolbox}"><Setter Property="SnapsToDevicePixels" Value="true"/><Setter Property="Focusable" Value="False"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type s:Toolbox}"><Border BorderThickness="{TemplateBinding Border.BorderThickness}"Padding="{TemplateBinding Control.Padding}"BorderBrush="{TemplateBinding Border.BorderBrush}"Background="{TemplateBinding Panel.Background}"SnapsToDevicePixels="True"><ScrollViewer VerticalScrollBarVisibility="Auto"><ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /></ScrollViewer></Border></ControlTemplate></Setter.Value></Setter><Setter Property="ItemsPanel"><Setter.Value><ItemsPanelTemplate><WrapPanel Margin="0,5,0,5"ItemHeight="{Binding Path=ItemSize.Height, RelativeSource={RelativeSource AncestorType=s:Toolbox}}"ItemWidth="{Binding Path=ItemSize.Width, RelativeSource={RelativeSource AncestorType=s:Toolbox}}"/></ItemsPanelTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

14、ToolboxItem.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="clr-namespace:DiagramDesigner"><Style TargetType="{x:Type s:ToolboxItem}"><Setter Property="Control.Padding" Value="10"/><Setter Property="ContentControl.HorizontalContentAlignment" Value="Stretch"/><Setter Property="ContentControl.VerticalContentAlignment" Value="Stretch"/><Setter Property="ToolTip" Value="{Binding ToolTip}"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type s:ToolboxItem}" ><Grid><Rectangle Name="Border"StrokeThickness="1"StrokeDashArray="2"Fill="Transparent"SnapsToDevicePixels="true"/><ContentPresenter Content="{TemplateBinding ContentControl.Content}"Margin="{TemplateBinding Padding}"SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="true"><Setter TargetName="Border" Property="Stroke" Value="Gray"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

15、DragThumb.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using System.Windows.Media;namespace DiagramDesigner.Controls
{/// <summary>/// 自定义Thumb控件(表示可以由用户拖动的控件)/// </summary>public class DragThumb : Thumb{public DragThumb(){base.DragDelta += new DragDeltaEventHandler(DragThumb_DragDelta);}/// <summary>/// 焦点和鼠标捕获处理/// </summary>/// <param name="sender"></param>/// <param name="e"></param>void DragThumb_DragDelta(object sender, DragDeltaEventArgs e){DesignerItem designerItem = this.DataContext as DesignerItem;DesignerCanvas designer = VisualTreeHelper.GetParent(designerItem) as DesignerCanvas;if (designerItem != null && designer != null && designerItem.IsSelected){double minLeft = double.MaxValue;double minTop = double.MaxValue;// we only move DesignerItemsvar designerItems = from item in designer.SelectedItemswhere item is DesignerItemselect item;foreach (DesignerItem item in designerItems){double left = Canvas.GetLeft(item);double top = Canvas.GetTop(item);minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);}double deltaHorizontal = Math.Max(-minLeft, e.HorizontalChange);double deltaVertical = Math.Max(-minTop, e.VerticalChange);foreach (DesignerItem item in designerItems){double left = Canvas.GetLeft(item);double top = Canvas.GetTop(item);if (double.IsNaN(left)) left = 0;if (double.IsNaN(top)) top = 0;Canvas.SetLeft(item, left + deltaHorizontal);Canvas.SetTop(item, top + deltaVertical);}designer.InvalidateMeasure();e.Handled = true;}}}
}

16、RelativePositionPanel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows;namespace DiagramDesigner.Controls
{public class RelativePositionPanel : Panel{public static readonly DependencyProperty RelativePositionProperty =DependencyProperty.RegisterAttached("RelativePosition", typeof(Point), typeof(RelativePositionPanel),new FrameworkPropertyMetadata(new Point(0, 0),new PropertyChangedCallback(RelativePositionPanel.OnRelativePositionChanged)));public static Point GetRelativePosition(UIElement element){if (element == null){throw new ArgumentNullException("element");}return (Point)element.GetValue(RelativePositionProperty);}public static void SetRelativePosition(UIElement element, Point value){if (element == null){throw new ArgumentNullException("element");}element.SetValue(RelativePositionProperty, value);}private static void OnRelativePositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){UIElement reference = d as UIElement;if (reference != null){RelativePositionPanel parent = VisualTreeHelper.GetParent(reference) as RelativePositionPanel;if (parent != null){parent.InvalidateArrange();}}}protected override Size ArrangeOverride(Size arrangeSize){foreach (UIElement element in base.InternalChildren){if (element != null){Point relPosition = GetRelativePosition(element);double x = (arrangeSize.Width - element.DesiredSize.Width) * relPosition.X;double y = (arrangeSize.Height - element.DesiredSize.Height) * relPosition.Y;if (double.IsNaN(x)) x = 0;if (double.IsNaN(y)) y = 0;element.Arrange(new Rect(new Point(x, y), element.DesiredSize));}}return arrangeSize;}protected override Size MeasureOverride(Size availableSize){Size size = new Size(double.PositiveInfinity, double.PositiveInfinity);// SDK docu says about InternalChildren Property: 'Classes that are derived from Panel // should use this property, instead of the Children property, for internal overrides // such as MeasureCore and ArrangeCore.foreach (UIElement element in this.InternalChildren){if (element != null)element.Measure(size);}return base.MeasureOverride(availableSize);}}
}

17、ResizeThumb.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows;namespace DiagramDesigner.Controls
{public class ResizeThumb : Thumb{public ResizeThumb(){base.DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta);}void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e){DesignerItem designerItem = this.DataContext as DesignerItem;DesignerCanvas designer = VisualTreeHelper.GetParent(designerItem) as DesignerCanvas;if (designerItem != null && designer != null && designerItem.IsSelected){double minLeft, minTop, minDeltaHorizontal, minDeltaVertical;double dragDeltaVertical, dragDeltaHorizontal;// only resize DesignerItemsvar selectedDesignerItems = from item in designer.SelectedItemswhere item is DesignerItemselect item;CalculateDragLimits(selectedDesignerItems, out minLeft, out minTop,out minDeltaHorizontal, out minDeltaVertical);foreach (DesignerItem item in selectedDesignerItems){if (item != null){switch (base.VerticalAlignment){case VerticalAlignment.Bottom:dragDeltaVertical = Math.Min(-e.VerticalChange, minDeltaVertical);item.Height = item.ActualHeight - dragDeltaVertical;break;case VerticalAlignment.Top:double top = Canvas.GetTop(item);dragDeltaVertical = Math.Min(Math.Max(-minTop, e.VerticalChange), minDeltaVertical);Canvas.SetTop(item, top + dragDeltaVertical);item.Height = item.ActualHeight - dragDeltaVertical;break;default:break;}switch (base.HorizontalAlignment){case HorizontalAlignment.Left:double left = Canvas.GetLeft(item);dragDeltaHorizontal = Math.Min(Math.Max(-minLeft, e.HorizontalChange), minDeltaHorizontal);Canvas.SetLeft(item, left + dragDeltaHorizontal);item.Width = item.ActualWidth - dragDeltaHorizontal;break;case HorizontalAlignment.Right:dragDeltaHorizontal = Math.Min(-e.HorizontalChange, minDeltaHorizontal);item.Width = item.ActualWidth - dragDeltaHorizontal;break;default:break;}}}e.Handled = true;}}private static void CalculateDragLimits(IEnumerable<ISelectable> selectedDesignerItems, out double minLeft, out double minTop, out double minDeltaHorizontal, out double minDeltaVertical){minLeft = double.MaxValue;minTop = double.MaxValue;minDeltaHorizontal = double.MaxValue;minDeltaVertical = double.MaxValue;// drag limits are set by these parameters: canvas top, canvas left, minHeight, minWidth// calculate min value for each parameter for each itemforeach (DesignerItem item in selectedDesignerItems){double left = Canvas.GetLeft(item);double top = Canvas.GetTop(item);minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);minDeltaVertical = Math.Min(minDeltaVertical, item.ActualHeight - item.MinHeight);minDeltaHorizontal = Math.Min(minDeltaHorizontal, item.ActualWidth - item.MinWidth);}}}
}

18、App.xaml

<Application x:Class="DiagramDesigner.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:DiagramDesigner"StartupUri="MainWindow.xaml"><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Assets\Styles\Shared.xaml"/><ResourceDictionary Source="Assets\Styles\ScrollBar.xaml"/><ResourceDictionary Source="Assets\Styles\Expander.xaml"/><ResourceDictionary Source="Assets\Styles\GroupBox.xaml"/><ResourceDictionary Source="Assets\Styles\ToolTip.xaml"/><ResourceDictionary Source="Assets\Styles\ScrollViewer.xaml"/></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>
</Application>

19、Connection.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;namespace DiagramDesigner
{public class Connection : Control, ISelectable, INotifyPropertyChanged{private Adorner connectionAdorner;#region Properties// source connectorprivate Connector source;public Connector Source{get{return source;}set{if (source != value){if (source != null){source.PropertyChanged -= new PropertyChangedEventHandler(OnConnectorPositionChanged);source.Connections.Remove(this);}source = value;if (source != null){source.Connections.Add(this);source.PropertyChanged += new PropertyChangedEventHandler(OnConnectorPositionChanged);}UpdatePathGeometry();}}}// sink connectorprivate Connector sink;public Connector Sink{get { return sink; }set{if (sink != value){if (sink != null){sink.PropertyChanged -= new PropertyChangedEventHandler(OnConnectorPositionChanged);sink.Connections.Remove(this);}sink = value;if (sink != null){sink.Connections.Add(this);sink.PropertyChanged += new PropertyChangedEventHandler(OnConnectorPositionChanged);}UpdatePathGeometry();}}}// connection path geometryprivate PathGeometry pathGeometry;public PathGeometry PathGeometry{get { return pathGeometry; }set{if (pathGeometry != value){pathGeometry = value;UpdateAnchorPosition();OnPropertyChanged("PathGeometry");}}}// between source connector position and the beginning // of the path geometry we leave some space for visual reasons; // so the anchor position source really marks the beginning // of the path geometry on the source sideprivate Point anchorPositionSource;public Point AnchorPositionSource{get { return anchorPositionSource; }set{if (anchorPositionSource != value){anchorPositionSource = value;OnPropertyChanged("AnchorPositionSource");}}}// slope of the path at the anchor position// needed for the rotation angle of the arrowprivate double anchorAngleSource = 0;public double AnchorAngleSource{get { return anchorAngleSource; }set{if (anchorAngleSource != value){anchorAngleSource = value;OnPropertyChanged("AnchorAngleSource");}}}// analogue to source sideprivate Point anchorPositionSink;public Point AnchorPositionSink{get { return anchorPositionSink; }set{if (anchorPositionSink != value){anchorPositionSink = value;OnPropertyChanged("AnchorPositionSink");}}}// analogue to source sideprivate double anchorAngleSink = 0;public double AnchorAngleSink{get { return anchorAngleSink; }set{if (anchorAngleSink != value){anchorAngleSink = value;OnPropertyChanged("AnchorAngleSink");}}}private ArrowSymbol sourceArrowSymbol = ArrowSymbol.None;public ArrowSymbol SourceArrowSymbol{get { return sourceArrowSymbol; }set{if (sourceArrowSymbol != value){sourceArrowSymbol = value;OnPropertyChanged("SourceArrowSymbol");}}}public ArrowSymbol sinkArrowSymbol = ArrowSymbol.Arrow;public ArrowSymbol SinkArrowSymbol{get { return sinkArrowSymbol; }set{if (sinkArrowSymbol != value){sinkArrowSymbol = value;OnPropertyChanged("SinkArrowSymbol");}}}// specifies a point at half path lengthprivate Point labelPosition;public Point LabelPosition{get { return labelPosition; }set{if (labelPosition != value){labelPosition = value;OnPropertyChanged("LabelPosition");}}}// pattern of dashes and gaps that is used to outline the connection pathprivate DoubleCollection strokeDashArray;public DoubleCollection StrokeDashArray{get{return strokeDashArray;}set{if (strokeDashArray != value){strokeDashArray = value;OnPropertyChanged("StrokeDashArray");}}}// if connected, the ConnectionAdorner becomes visibleprivate bool isSelected;public bool IsSelected{get { return isSelected; }set{if (isSelected != value){isSelected = value;OnPropertyChanged("IsSelected");if (isSelected)ShowAdorner();elseHideAdorner();}}}#endregionpublic Connection(Connector source, Connector sink){this.Source = source;this.Sink = sink;base.Unloaded += new RoutedEventHandler(Connection_Unloaded);}protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e){base.OnMouseDown(e);// usual selection businessDesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;if (designer != null)if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != ModifierKeys.None)if (this.IsSelected){this.IsSelected = false;designer.SelectedItems.Remove(this);}else{this.IsSelected = true;designer.SelectedItems.Add(this);}else if (!this.IsSelected){foreach (ISelectable item in designer.SelectedItems)item.IsSelected = false;designer.SelectedItems.Clear();this.IsSelected = true;designer.SelectedItems.Add(this);}e.Handled = false;}void OnConnectorPositionChanged(object sender, PropertyChangedEventArgs e){// whenever the 'Position' property of the source or sink Connector // changes we must update the connection path geometryif (e.PropertyName.Equals("Position")){UpdatePathGeometry();}}private void UpdatePathGeometry(){if (Source != null && Sink != null){PathGeometry geometry = new PathGeometry();List<Point> linePoints = PathFinder.GetConnectionLine(Source.GetInfo(), Sink.GetInfo(), true);if (linePoints.Count > 0){PathFigure figure = new PathFigure();figure.StartPoint = linePoints[0];linePoints.Remove(linePoints[0]);figure.Segments.Add(new PolyLineSegment(linePoints, true));geometry.Figures.Add(figure);this.PathGeometry = geometry;}}}private void UpdateAnchorPosition(){Point pathStartPoint, pathTangentAtStartPoint;Point pathEndPoint, pathTangentAtEndPoint;Point pathMidPoint, pathTangentAtMidPoint;// the PathGeometry.GetPointAtFractionLength method gets the point and a tangent vector // on PathGeometry at the specified fraction of its lengththis.PathGeometry.GetPointAtFractionLength(0, out pathStartPoint, out pathTangentAtStartPoint);this.PathGeometry.GetPointAtFractionLength(1, out pathEndPoint, out pathTangentAtEndPoint);this.PathGeometry.GetPointAtFractionLength(0.5, out pathMidPoint, out pathTangentAtMidPoint);// get angle from tangent vectorthis.AnchorAngleSource = Math.Atan2(-pathTangentAtStartPoint.Y, -pathTangentAtStartPoint.X) * (180 / Math.PI);this.AnchorAngleSink = Math.Atan2(pathTangentAtEndPoint.Y, pathTangentAtEndPoint.X) * (180 / Math.PI);// add some margin on source and sink side for visual reasons onlypathStartPoint.Offset(-pathTangentAtStartPoint.X * 5, -pathTangentAtStartPoint.Y * 5);pathEndPoint.Offset(pathTangentAtEndPoint.X * 5, pathTangentAtEndPoint.Y * 5);this.AnchorPositionSource = pathStartPoint;this.AnchorPositionSink = pathEndPoint;this.LabelPosition = pathMidPoint;}private void ShowAdorner(){// the ConnectionAdorner is created once for each Connectionif (this.connectionAdorner == null){DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(designer);if (adornerLayer != null){this.connectionAdorner = new ConnectionAdorner(designer, this);adornerLayer.Add(this.connectionAdorner);}}this.connectionAdorner.Visibility = Visibility.Visible;}internal void HideAdorner(){if (this.connectionAdorner != null)this.connectionAdorner.Visibility = Visibility.Collapsed;}void Connection_Unloaded(object sender, RoutedEventArgs e){// do some housekeeping when Connection is unloaded// remove event handlersource.PropertyChanged -= new PropertyChangedEventHandler(OnConnectorPositionChanged);sink.PropertyChanged -= new PropertyChangedEventHandler(OnConnectorPositionChanged);// remove adornerif (this.connectionAdorner != null){DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(designer);if (adornerLayer != null){adornerLayer.Remove(this.connectionAdorner);this.connectionAdorner = null;}}}#region INotifyPropertyChanged Members// we could use DependencyProperties as well to inform others of property changespublic event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string name){PropertyChangedEventHandler handler = PropertyChanged;if (handler != null){handler(this, new PropertyChangedEventArgs(name));}}#endregion}public enum ArrowSymbol{None,Arrow,Diamond}
}

20、ConnectionAdorner.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;namespace DiagramDesigner
{public class ConnectionAdorner : Adorner{private DesignerCanvas designerCanvas;private Canvas adornerCanvas;private Connection connection;private PathGeometry pathGeometry;private Connector fixConnector, dragConnector;private Thumb sourceDragThumb, sinkDragThumb;private Pen drawingPen;private DesignerItem hitDesignerItem;private DesignerItem HitDesignerItem{get { return hitDesignerItem; }set{if (hitDesignerItem != value){if (hitDesignerItem != null)hitDesignerItem.IsDragConnectionOver = false;hitDesignerItem = value;if (hitDesignerItem != null)hitDesignerItem.IsDragConnectionOver = true;}}}private Connector hitConnector;private Connector HitConnector{get { return hitConnector; }set{if (hitConnector != value){hitConnector = value;}}}private VisualCollection visualChildren;protected override int VisualChildrenCount{get{return this.visualChildren.Count;}}protected override Visual GetVisualChild(int index){return this.visualChildren[index];}public ConnectionAdorner(DesignerCanvas designer, Connection connection): base(designer){this.designerCanvas = designer;adornerCanvas = new Canvas();this.visualChildren = new VisualCollection(this);this.visualChildren.Add(adornerCanvas);this.connection = connection;this.connection.PropertyChanged += new PropertyChangedEventHandler(AnchorPositionChanged);InitializeDragThumbs();drawingPen = new Pen(Brushes.LightSlateGray, 1);drawingPen.LineJoin = PenLineJoin.Round;}private void InitializeDragThumbs(){Style dragThumbStyle = connection.FindResource("ConnectionAdornerThumbStyle") as Style;//source drag thumbsourceDragThumb = new Thumb();Canvas.SetLeft(sourceDragThumb, connection.AnchorPositionSource.X);Canvas.SetTop(sourceDragThumb, connection.AnchorPositionSource.Y);this.adornerCanvas.Children.Add(sourceDragThumb);if (dragThumbStyle != null)sourceDragThumb.Style = dragThumbStyle;sourceDragThumb.DragDelta += new DragDeltaEventHandler(thumbDragThumb_DragDelta);sourceDragThumb.DragStarted += new DragStartedEventHandler(thumbDragThumb_DragStarted);sourceDragThumb.DragCompleted += new DragCompletedEventHandler(thumbDragThumb_DragCompleted);// sink drag thumbsinkDragThumb = new Thumb();Canvas.SetLeft(sinkDragThumb, connection.AnchorPositionSink.X);Canvas.SetTop(sinkDragThumb, connection.AnchorPositionSink.Y);this.adornerCanvas.Children.Add(sinkDragThumb);if (dragThumbStyle != null)sinkDragThumb.Style = dragThumbStyle;sinkDragThumb.DragDelta += new DragDeltaEventHandler(thumbDragThumb_DragDelta);sinkDragThumb.DragStarted += new DragStartedEventHandler(thumbDragThumb_DragStarted);sinkDragThumb.DragCompleted += new DragCompletedEventHandler(thumbDragThumb_DragCompleted);}void AnchorPositionChanged(object sender, PropertyChangedEventArgs e){if (e.PropertyName.Equals("AnchorPositionSource")){Canvas.SetLeft(sourceDragThumb, connection.AnchorPositionSource.X);Canvas.SetTop(sourceDragThumb, connection.AnchorPositionSource.Y);}if (e.PropertyName.Equals("AnchorPositionSink")){Canvas.SetLeft(sinkDragThumb, connection.AnchorPositionSink.X);Canvas.SetTop(sinkDragThumb, connection.AnchorPositionSink.Y);}}void thumbDragThumb_DragCompleted(object sender, DragCompletedEventArgs e){if (HitConnector != null){if (connection != null){if (connection.Source == fixConnector)connection.Sink = this.HitConnector;elseconnection.Source = this.HitConnector;}}this.HitDesignerItem = null;this.HitConnector = null;this.pathGeometry = null;this.connection.StrokeDashArray = null;this.InvalidateVisual();}void thumbDragThumb_DragStarted(object sender, DragStartedEventArgs e){this.HitDesignerItem = null;this.HitConnector = null;this.pathGeometry = null;this.Cursor = Cursors.Cross;this.connection.StrokeDashArray = new DoubleCollection(new double[] { 1, 2 });if (sender == sourceDragThumb){fixConnector = connection.Sink;dragConnector = connection.Source;}else if (sender == sinkDragThumb){dragConnector = connection.Sink;fixConnector = connection.Source;}}void thumbDragThumb_DragDelta(object sender, DragDeltaEventArgs e){Point currentPosition = Mouse.GetPosition(this);this.HitTesting(currentPosition);this.pathGeometry = UpdatePathGeometry(currentPosition);this.InvalidateVisual();}protected override void OnRender(DrawingContext dc){base.OnRender(dc);dc.DrawGeometry(null, drawingPen, this.pathGeometry);}protected override Size ArrangeOverride(Size finalSize){adornerCanvas.Arrange(new Rect(0, 0, this.designerCanvas.ActualWidth, this.designerCanvas.ActualHeight));return finalSize;}private PathGeometry UpdatePathGeometry(Point position){PathGeometry geometry = new PathGeometry();ConnectorOrientation targetOrientation;if (HitConnector != null)targetOrientation = HitConnector.Orientation;elsetargetOrientation = dragConnector.Orientation;List<Point> linePoints = PathFinder.GetConnectionLine(fixConnector.GetInfo(), position, targetOrientation);if (linePoints.Count > 0){PathFigure figure = new PathFigure();figure.StartPoint = linePoints[0];linePoints.Remove(linePoints[0]);figure.Segments.Add(new PolyLineSegment(linePoints, true));geometry.Figures.Add(figure);}return geometry;}private void HitTesting(Point hitPoint){bool hitConnectorFlag = false;DependencyObject hitObject = designerCanvas.InputHitTest(hitPoint) as DependencyObject;while (hitObject != null &&hitObject != fixConnector.ParentDesignerItem &&hitObject.GetType() != typeof(DesignerCanvas)){if (hitObject is Connector){HitConnector = hitObject as Connector;hitConnectorFlag = true;}if (hitObject is DesignerItem){HitDesignerItem = hitObject as DesignerItem;if (!hitConnectorFlag)HitConnector = null;return;}hitObject = VisualTreeHelper.GetParent(hitObject);}HitConnector = null;HitDesignerItem = null;}}
}

21、Connector.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;namespace DiagramDesigner
{public class Connector : Control, INotifyPropertyChanged{// drag start point, relative to the DesignerCanvasprivate Point? dragStartPoint = null;public ConnectorOrientation Orientation { get; set; }// center position of this Connector relative to the DesignerCanvasprivate Point position;public Point Position{get { return position; }set{if (position != value){position = value;OnPropertyChanged("Position");}}}// the DesignerItem this Connector belongs to;// retrieved from DataContext, which is set in the// DesignerItem templateprivate DesignerItem parentDesignerItem;public DesignerItem ParentDesignerItem{get{if (parentDesignerItem == null)parentDesignerItem = this.DataContext as DesignerItem;return parentDesignerItem;}}// keep track of connections that link to this connectorprivate List<Connection> connections;public List<Connection> Connections{get{if (connections == null)connections = new List<Connection>();return connections;}}public Connector(){// fired when layout changesbase.LayoutUpdated += new EventHandler(Connector_LayoutUpdated);}// when the layout changes we update the position propertyvoid Connector_LayoutUpdated(object sender, EventArgs e){DesignerCanvas designer = GetDesignerCanvas(this);if (designer != null){//get centre position of this Connector relative to the DesignerCanvasthis.Position = this.TransformToAncestor(designer).Transform(new Point(this.Width / 2, this.Height / 2));}}protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e){base.OnMouseLeftButtonDown(e);DesignerCanvas canvas = GetDesignerCanvas(this);if (canvas != null){// position relative to DesignerCanvasthis.dragStartPoint = new Point?(e.GetPosition(canvas));e.Handled = true;}}protected override void OnMouseMove(MouseEventArgs e){base.OnMouseMove(e);// if mouse button is not pressed we have no drag operation, ...if (e.LeftButton != MouseButtonState.Pressed)this.dragStartPoint = null;// but if mouse button is pressed and start point value is set we do have oneif (this.dragStartPoint.HasValue){// create connection adorner DesignerCanvas canvas = GetDesignerCanvas(this);if (canvas != null){AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(canvas);if (adornerLayer != null){ConnectorAdorner adorner = new ConnectorAdorner(canvas, this);if (adorner != null){adornerLayer.Add(adorner);e.Handled = true;}}}}}internal ConnectorInfo GetInfo(){ConnectorInfo info = new ConnectorInfo();info.DesignerItemLeft = DesignerCanvas.GetLeft(this.ParentDesignerItem);info.DesignerItemTop = DesignerCanvas.GetTop(this.ParentDesignerItem);info.DesignerItemSize = new Size(this.ParentDesignerItem.ActualWidth, this.ParentDesignerItem.ActualHeight);info.Orientation = this.Orientation;info.Position = this.Position;return info;}// iterate through visual tree to get parent DesignerCanvasprivate DesignerCanvas GetDesignerCanvas(DependencyObject element){while (element != null && !(element is DesignerCanvas))element = VisualTreeHelper.GetParent(element);return element as DesignerCanvas;}#region INotifyPropertyChanged Members// we could use DependencyProperties as well to inform others of property changespublic event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string name){PropertyChangedEventHandler handler = PropertyChanged;if (handler != null){handler(this, new PropertyChangedEventArgs(name));}}#endregion}// provides compact info about a connector; used for the // routing algorithm, instead of hand over a full fledged Connectorinternal struct ConnectorInfo{public double DesignerItemLeft { get; set; }public double DesignerItemTop { get; set; }public Size DesignerItemSize { get; set; }public Point Position { get; set; }public ConnectorOrientation Orientation { get; set; }}public enum ConnectorOrientation{None,Left,Top,Right,Bottom}
}

22、ConnectorAdorner.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;namespace DiagramDesigner
{public class ConnectorAdorner : Adorner{private PathGeometry pathGeometry;private DesignerCanvas designerCanvas;private Connector sourceConnector;private Pen drawingPen;private DesignerItem hitDesignerItem;private DesignerItem HitDesignerItem{get { return hitDesignerItem; }set{if (hitDesignerItem != value){if (hitDesignerItem != null)hitDesignerItem.IsDragConnectionOver = false;hitDesignerItem = value;if (hitDesignerItem != null)hitDesignerItem.IsDragConnectionOver = true;}}}private Connector hitConnector;private Connector HitConnector{get { return hitConnector; }set{if (hitConnector != value){hitConnector = value;}}}public ConnectorAdorner(DesignerCanvas designer, Connector sourceConnector): base(designer){this.designerCanvas = designer;this.sourceConnector = sourceConnector;drawingPen = new Pen(Brushes.LightSlateGray, 1);drawingPen.LineJoin = PenLineJoin.Round;this.Cursor = Cursors.Cross;}protected override void OnMouseUp(MouseButtonEventArgs e){if (HitConnector != null){Connector sourceConnector = this.sourceConnector;Connector sinkConnector = this.HitConnector;Connection newConnection = new Connection(sourceConnector, sinkConnector);// connections are added with z-index of zerothis.designerCanvas.Children.Insert(0, newConnection);}if (HitDesignerItem != null){this.HitDesignerItem.IsDragConnectionOver = false;}if (this.IsMouseCaptured) this.ReleaseMouseCapture();AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.designerCanvas);if (adornerLayer != null){adornerLayer.Remove(this);}}protected override void OnMouseMove(MouseEventArgs e){if (e.LeftButton == MouseButtonState.Pressed){if (!this.IsMouseCaptured) this.CaptureMouse();HitTesting(e.GetPosition(this));this.pathGeometry = GetPathGeometry(e.GetPosition(this));this.InvalidateVisual();}else{if (this.IsMouseCaptured) this.ReleaseMouseCapture();}}protected override void OnRender(DrawingContext dc){base.OnRender(dc);dc.DrawGeometry(null, drawingPen, this.pathGeometry);// without a background the OnMouseMove event would not be fired// Alternative: implement a Canvas as a child of this adorner, like// the ConnectionAdorner does.dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));}private PathGeometry GetPathGeometry(Point position){PathGeometry geometry = new PathGeometry();ConnectorOrientation targetOrientation;if (HitConnector != null)targetOrientation = HitConnector.Orientation;elsetargetOrientation = ConnectorOrientation.None;List<Point> pathPoints = PathFinder.GetConnectionLine(sourceConnector.GetInfo(), position, targetOrientation);if (pathPoints.Count > 0){PathFigure figure = new PathFigure();figure.StartPoint = pathPoints[0];pathPoints.Remove(pathPoints[0]);figure.Segments.Add(new PolyLineSegment(pathPoints, true));geometry.Figures.Add(figure);}return geometry;}private void HitTesting(Point hitPoint){bool hitConnectorFlag = false;DependencyObject hitObject = designerCanvas.InputHitTest(hitPoint) as DependencyObject;while (hitObject != null &&hitObject != sourceConnector.ParentDesignerItem &&hitObject.GetType() != typeof(DesignerCanvas)){if (hitObject is Connector){HitConnector = hitObject as Connector;hitConnectorFlag = true;}if (hitObject is DesignerItem){HitDesignerItem = hitObject as DesignerItem;if (!hitConnectorFlag)HitConnector = null;return;}hitObject = VisualTreeHelper.GetParent(hitObject);}HitConnector = null;HitDesignerItem = null;}}
}

23、DesignerCanvas.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows;
using System.Xml;
using System.Windows.Markup;namespace DiagramDesigner
{public class DesignerCanvas : Canvas{// start point of the rubberband drag operationprivate Point? rubberbandSelectionStartPoint = null;// keep track of selected items private List<ISelectable> selectedItems;public List<ISelectable> SelectedItems{get{if (selectedItems == null)selectedItems = new List<ISelectable>();return selectedItems;}set{selectedItems = value;}}public DesignerCanvas(){this.AllowDrop = true;}protected override void OnMouseDown(MouseButtonEventArgs e){base.OnMouseDown(e);if (e.Source == this){// in case that this click is the start for a // drag operation we cache the start pointthis.rubberbandSelectionStartPoint = new Point?(e.GetPosition(this));// if you click directly on the canvas all // selected items are 'de-selected'foreach (ISelectable item in SelectedItems)item.IsSelected = false;selectedItems.Clear();e.Handled = true;}}protected override void OnMouseMove(MouseEventArgs e){base.OnMouseMove(e);// if mouse button is not pressed we have no drag operation, ...if (e.LeftButton != MouseButtonState.Pressed)this.rubberbandSelectionStartPoint = null;// ... but if mouse button is pressed and start// point value is set we do have oneif (this.rubberbandSelectionStartPoint.HasValue){// create rubberband adornerAdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);if (adornerLayer != null){RubberbandAdorner adorner = new RubberbandAdorner(this, rubberbandSelectionStartPoint);if (adorner != null){adornerLayer.Add(adorner);}}}e.Handled = true;}protected override void OnDrop(DragEventArgs e){base.OnDrop(e);DragObject dragObject = e.Data.GetData(typeof(DragObject)) as DragObject;if (dragObject != null && !String.IsNullOrEmpty(dragObject.Xaml)){DesignerItem newItem = null;Object content = XamlReader.Load(XmlReader.Create(new StringReader(dragObject.Xaml)));if (content != null){newItem = new DesignerItem();newItem.Content = content;Point position = e.GetPosition(this);if (dragObject.DesiredSize.HasValue){Size desiredSize = dragObject.DesiredSize.Value;newItem.Width = desiredSize.Width;newItem.Height = desiredSize.Height;DesignerCanvas.SetLeft(newItem, Math.Max(0, position.X - newItem.Width / 2));DesignerCanvas.SetTop(newItem, Math.Max(0, position.Y - newItem.Height / 2));}else{DesignerCanvas.SetLeft(newItem, Math.Max(0, position.X));DesignerCanvas.SetTop(newItem, Math.Max(0, position.Y));}this.Children.Add(newItem);//update selectionforeach (ISelectable item in this.SelectedItems)item.IsSelected = false;SelectedItems.Clear();newItem.IsSelected = true;this.SelectedItems.Add(newItem);}e.Handled = true;}}protected override Size MeasureOverride(Size constraint){Size size = new Size();foreach (UIElement element in base.Children){double left = Canvas.GetLeft(element);double top = Canvas.GetTop(element);left = double.IsNaN(left) ? 0 : left;top = double.IsNaN(top) ? 0 : top;//measure desired size for each childelement.Measure(constraint);Size desiredSize = element.DesiredSize;if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height)){size.Width = Math.Max(size.Width, left + desiredSize.Width);size.Height = Math.Max(size.Height, top + desiredSize.Height);}}// add margin size.Width += 10;size.Height += 10;return size;}}
}

24、DesignerItem.cs

using DiagramDesigner.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;
using System.Xml.Linq;namespace DiagramDesigner
{//These attributes identify the types of the named parts that are used for templating[TemplatePart(Name = "PART_DragThumb", Type = typeof(DragThumb))][TemplatePart(Name = "PART_ResizeDecorator", Type = typeof(Control))][TemplatePart(Name = "PART_ConnectorDecorator", Type = typeof(Control))][TemplatePart(Name = "PART_ContentPresenter", Type = typeof(ContentPresenter))]public class DesignerItem : ContentControl, ISelectable{#region IsSelected Property是否选中public bool IsSelected{get { return (bool)GetValue(IsSelectedProperty); }set { SetValue(IsSelectedProperty, value); }}public static readonly DependencyProperty IsSelectedProperty =DependencyProperty.Register("IsSelected",typeof(bool),typeof(DesignerItem),new FrameworkPropertyMetadata(false));#endregion#region DragThumbTemplate Property拖拽thumb模板// can be used to replace the default template for the DragThumbpublic static readonly DependencyProperty DragThumbTemplateProperty =DependencyProperty.RegisterAttached("DragThumbTemplate", typeof(ControlTemplate), typeof(DesignerItem));public static ControlTemplate GetDragThumbTemplate(UIElement element){return (ControlTemplate)element.GetValue(DragThumbTemplateProperty);}public static void SetDragThumbTemplate(UIElement element, ControlTemplate value){element.SetValue(DragThumbTemplateProperty, value);}#endregion#region ConnectorDecoratorTemplate Property连接器模板// can be used to replace the default template for the ConnectorDecoratorpublic static readonly DependencyProperty ConnectorDecoratorTemplateProperty =DependencyProperty.RegisterAttached("ConnectorDecoratorTemplate", typeof(ControlTemplate), typeof(DesignerItem));public static ControlTemplate GetConnectorDecoratorTemplate(UIElement element){return (ControlTemplate)element.GetValue(ConnectorDecoratorTemplateProperty);}public static void SetConnectorDecoratorTemplate(UIElement element, ControlTemplate value){element.SetValue(ConnectorDecoratorTemplateProperty, value);}#endregion#region IsDragConnectionOver拖拽链接是否结束// while drag connection procedure is ongoing and the mouse moves over // this item this value is true; if true the ConnectorDecorator is triggered// to be visible, see template -- 当拖动连接过程正在进行并且鼠标移动到此项目上时,此值为真;//如果为true,则会触发ConnectorDecorator使其可见,请参阅模板public bool IsDragConnectionOver{get { return (bool)GetValue(IsDragConnectionOverProperty); }set { SetValue(IsDragConnectionOverProperty, value); }}public static readonly DependencyProperty IsDragConnectionOverProperty =DependencyProperty.Register("IsDragConnectionOver",typeof(bool),typeof(DesignerItem),new FrameworkPropertyMetadata(false));#endregionstatic DesignerItem(){// set the key to reference the style for this control--设置键以引用此控件的样式FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(DesignerItem), new FrameworkPropertyMetadata(typeof(DesignerItem)));}public DesignerItem(){this.Loaded += new RoutedEventHandler(DesignerItem_Loaded);}protected override void OnPreviewMouseDown(MouseButtonEventArgs e){base.OnPreviewMouseDown(e);DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;// update selectionif (designer != null)if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != ModifierKeys.None)if (this.IsSelected){this.IsSelected = false;designer.SelectedItems.Remove(this);}else{this.IsSelected = true;designer.SelectedItems.Add(this);}else if (!this.IsSelected){foreach (ISelectable item in designer.SelectedItems)item.IsSelected = false;designer.SelectedItems.Clear();this.IsSelected = true;designer.SelectedItems.Add(this);}e.Handled = false;}void DesignerItem_Loaded(object sender, RoutedEventArgs e){// if DragThumbTemplate and ConnectorDecoratorTemplate properties of this class// are set these templates are applied; // Note: this method is only executed when the Loaded event is fired, so// setting DragThumbTemplate or ConnectorDecoratorTemplate properties after// will have no effect.if (base.Template != null){ContentPresenter contentPresenter =this.Template.FindName("PART_ContentPresenter", this) as ContentPresenter;if (contentPresenter != null){UIElement contentVisual = VisualTreeHelper.GetChild(contentPresenter, 0) as UIElement;if (contentVisual != null){DragThumb thumb = this.Template.FindName("PART_DragThumb", this) as DragThumb;Control connectorDecorator = this.Template.FindName("PART_ConnectorDecorator", this) as Control;if (thumb != null){ControlTemplate template =DesignerItem.GetDragThumbTemplate(contentVisual) as ControlTemplate;if (template != null)thumb.Template = template;}if (connectorDecorator != null){ControlTemplate template =DesignerItem.GetConnectorDecoratorTemplate(contentVisual) as ControlTemplate;if (template != null)connectorDecorator.Template = template;}}}}}}
}

25、ISelectable.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace DiagramDesigner
{// Common interface for items that can be selected// on the DesignerCanvas; used by DesignerItem and Connectionpublic interface ISelectable{bool IsSelected { get; set; }}
}

26、PathFinder.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;namespace DiagramDesigner
{// Note: I couldn't find a useful open source library that does// orthogonal routing so started to write something on my own.// Categorize this as a quick and dirty short term solution.// I will keep on searching.// Helper class to provide an orthogonal connection pathinternal class PathFinder{private const int margin = 20;internal static List<Point> GetConnectionLine(ConnectorInfo source, ConnectorInfo sink, bool showLastLine){List<Point> linePoints = new List<Point>();Rect rectSource = GetRectWithMargin(source, margin);Rect rectSink = GetRectWithMargin(sink, margin);Point startPoint = GetOffsetPoint(source, rectSource);Point endPoint = GetOffsetPoint(sink, rectSink);linePoints.Add(startPoint);Point currentPoint = startPoint;if (!rectSink.Contains(currentPoint) && !rectSource.Contains(endPoint)){while (true){#region source nodeif (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource, rectSink })){linePoints.Add(endPoint);currentPoint = endPoint;break;}Point neighbour = GetNearestVisibleNeighborSink(currentPoint, endPoint, sink, rectSource, rectSink);if (!double.IsNaN(neighbour.X)){linePoints.Add(neighbour);linePoints.Add(endPoint);currentPoint = endPoint;break;}if (currentPoint == startPoint){bool flag;Point n = GetNearestNeighborSource(source, endPoint, rectSource, rectSink, out flag);linePoints.Add(n);currentPoint = n;if (!IsRectVisible(currentPoint, rectSink, new Rect[] { rectSource })){Point n1, n2;GetOppositeCorners(source.Orientation, rectSource, out n1, out n2);if (flag){linePoints.Add(n1);currentPoint = n1;}else{linePoints.Add(n2);currentPoint = n2;}if (!IsRectVisible(currentPoint, rectSink, new Rect[] { rectSource })){if (flag){linePoints.Add(n2);currentPoint = n2;}else{linePoints.Add(n1);currentPoint = n1;}}}}#endregion#region sink nodeelse // from here on we jump to the sink node{Point n1, n2; // neighbour cornerPoint s1, s2; // opposite cornerGetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);GetOppositeCorners(sink.Orientation, rectSink, out n1, out n2);bool n1Visible = IsPointVisible(currentPoint, n1, new Rect[] { rectSource, rectSink });bool n2Visible = IsPointVisible(currentPoint, n2, new Rect[] { rectSource, rectSink });if (n1Visible && n2Visible){if (rectSource.Contains(n1)){linePoints.Add(n2);if (rectSource.Contains(s2)){linePoints.Add(n1);linePoints.Add(s1);}elselinePoints.Add(s2);linePoints.Add(endPoint);currentPoint = endPoint;break;}if (rectSource.Contains(n2)){linePoints.Add(n1);if (rectSource.Contains(s1)){linePoints.Add(n2);linePoints.Add(s2);}elselinePoints.Add(s1);linePoints.Add(endPoint);currentPoint = endPoint;break;}if ((Distance(n1, endPoint) <= Distance(n2, endPoint))){linePoints.Add(n1);if (rectSource.Contains(s1)){linePoints.Add(n2);linePoints.Add(s2);}elselinePoints.Add(s1);linePoints.Add(endPoint);currentPoint = endPoint;break;}else{linePoints.Add(n2);if (rectSource.Contains(s2)){linePoints.Add(n1);linePoints.Add(s1);}elselinePoints.Add(s2);linePoints.Add(endPoint);currentPoint = endPoint;break;}}else if (n1Visible){linePoints.Add(n1);if (rectSource.Contains(s1)){linePoints.Add(n2);linePoints.Add(s2);}elselinePoints.Add(s1);linePoints.Add(endPoint);currentPoint = endPoint;break;}else{linePoints.Add(n2);if (rectSource.Contains(s2)){linePoints.Add(n1);linePoints.Add(s1);}elselinePoints.Add(s2);linePoints.Add(endPoint);currentPoint = endPoint;break;}}#endregion}}else{linePoints.Add(endPoint);}linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource, rectSink }, source.Orientation, sink.Orientation);CheckPathEnd(source, sink, showLastLine, linePoints);return linePoints;}internal static List<Point> GetConnectionLine(ConnectorInfo source, Point sinkPoint, ConnectorOrientation preferredOrientation){List<Point> linePoints = new List<Point>();Rect rectSource = GetRectWithMargin(source, 10);Point startPoint = GetOffsetPoint(source, rectSource);Point endPoint = sinkPoint;linePoints.Add(startPoint);Point currentPoint = startPoint;if (!rectSource.Contains(endPoint)){while (true){if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource })){linePoints.Add(endPoint);break;}bool sideFlag;Point n = GetNearestNeighborSource(source, endPoint, rectSource, out sideFlag);linePoints.Add(n);currentPoint = n;if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource })){linePoints.Add(endPoint);break;}else{Point n1, n2;GetOppositeCorners(source.Orientation, rectSource, out n1, out n2);if (sideFlag)linePoints.Add(n1);elselinePoints.Add(n2);linePoints.Add(endPoint);break;}}}else{linePoints.Add(endPoint);}if (preferredOrientation != ConnectorOrientation.None)linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource }, source.Orientation, preferredOrientation);elselinePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource }, source.Orientation, GetOpositeOrientation(source.Orientation));return linePoints;}private static List<Point> OptimizeLinePoints(List<Point> linePoints, Rect[] rectangles, ConnectorOrientation sourceOrientation, ConnectorOrientation sinkOrientation){List<Point> points = new List<Point>();int cut = 0;for (int i = 0; i < linePoints.Count; i++){if (i >= cut){for (int k = linePoints.Count - 1; k > i; k--){if (IsPointVisible(linePoints[i], linePoints[k], rectangles)){cut = k;break;}}points.Add(linePoints[i]);}}#region Linefor (int j = 0; j < points.Count - 1; j++){if (points[j].X != points[j + 1].X && points[j].Y != points[j + 1].Y){ConnectorOrientation orientationFrom;ConnectorOrientation orientationTo;// orientation from pointif (j == 0)orientationFrom = sourceOrientation;elseorientationFrom = GetOrientation(points[j], points[j - 1]);// orientation to pint if (j == points.Count - 2)orientationTo = sinkOrientation;elseorientationTo = GetOrientation(points[j + 1], points[j + 2]);if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&(orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right)){double centerX = Math.Min(points[j].X, points[j + 1].X) + Math.Abs(points[j].X - points[j + 1].X) / 2;points.Insert(j + 1, new Point(centerX, points[j].Y));points.Insert(j + 2, new Point(centerX, points[j + 2].Y));if (points.Count - 1 > j + 3)points.RemoveAt(j + 3);return points;}if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&(orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom)){double centerY = Math.Min(points[j].Y, points[j + 1].Y) + Math.Abs(points[j].Y - points[j + 1].Y) / 2;points.Insert(j + 1, new Point(points[j].X, centerY));points.Insert(j + 2, new Point(points[j + 2].X, centerY));if (points.Count - 1 > j + 3)points.RemoveAt(j + 3);return points;}if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&(orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom)){points.Insert(j + 1, new Point(points[j + 1].X, points[j].Y));return points;}if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&(orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right)){points.Insert(j + 1, new Point(points[j].X, points[j + 1].Y));return points;}}}#endregionreturn points;}private static ConnectorOrientation GetOrientation(Point p1, Point p2){if (p1.X == p2.X){if (p1.Y >= p2.Y)return ConnectorOrientation.Bottom;elsereturn ConnectorOrientation.Top;}else if (p1.Y == p2.Y){if (p1.X >= p2.X)return ConnectorOrientation.Right;elsereturn ConnectorOrientation.Left;}throw new Exception("Failed to retrieve orientation");}private static Orientation GetOrientation(ConnectorOrientation sourceOrientation){switch (sourceOrientation){case ConnectorOrientation.Left:return Orientation.Horizontal;case ConnectorOrientation.Top:return Orientation.Vertical;case ConnectorOrientation.Right:return Orientation.Horizontal;case ConnectorOrientation.Bottom:return Orientation.Vertical;default:throw new Exception("Unknown ConnectorOrientation");}}private static Point GetNearestNeighborSource(ConnectorInfo source, Point endPoint, Rect rectSource, Rect rectSink, out bool flag){Point n1, n2; // neighborsGetNeighborCorners(source.Orientation, rectSource, out n1, out n2);if (rectSink.Contains(n1)){flag = false;return n2;}if (rectSink.Contains(n2)){flag = true;return n1;}if ((Distance(n1, endPoint) <= Distance(n2, endPoint))){flag = true;return n1;}else{flag = false;return n2;}}private static Point GetNearestNeighborSource(ConnectorInfo source, Point endPoint, Rect rectSource, out bool flag){Point n1, n2; // neighborsGetNeighborCorners(source.Orientation, rectSource, out n1, out n2);if ((Distance(n1, endPoint) <= Distance(n2, endPoint))){flag = true;return n1;}else{flag = false;return n2;}}private static Point GetNearestVisibleNeighborSink(Point currentPoint, Point endPoint, ConnectorInfo sink, Rect rectSource, Rect rectSink){Point s1, s2; // neighbors on sink sideGetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);bool flag1 = IsPointVisible(currentPoint, s1, new Rect[] { rectSource, rectSink });bool flag2 = IsPointVisible(currentPoint, s2, new Rect[] { rectSource, rectSink });if (flag1) // s1 visible{if (flag2) // s1 and s2 visible{if (rectSink.Contains(s1))return s2;if (rectSink.Contains(s2))return s1;if ((Distance(s1, endPoint) <= Distance(s2, endPoint)))return s1;elsereturn s2;}else{return s1;}}else // s1 not visible{if (flag2) // only s2 visible{return s2;}else // s1 and s2 not visible{return new Point(double.NaN, double.NaN);}}}private static bool IsPointVisible(Point fromPoint, Point targetPoint, Rect[] rectangles){foreach (Rect rect in rectangles){if (RectangleIntersectsLine(rect, fromPoint, targetPoint))return false;}return true;}private static bool IsRectVisible(Point fromPoint, Rect targetRect, Rect[] rectangles){if (IsPointVisible(fromPoint, targetRect.TopLeft, rectangles))return true;if (IsPointVisible(fromPoint, targetRect.TopRight, rectangles))return true;if (IsPointVisible(fromPoint, targetRect.BottomLeft, rectangles))return true;if (IsPointVisible(fromPoint, targetRect.BottomRight, rectangles))return true;return false;}private static bool RectangleIntersectsLine(Rect rect, Point startPoint, Point endPoint){rect.Inflate(-1, -1);return rect.IntersectsWith(new Rect(startPoint, endPoint));}private static void GetOppositeCorners(ConnectorOrientation orientation, Rect rect, out Point n1, out Point n2){switch (orientation){case ConnectorOrientation.Left:n1 = rect.TopRight; n2 = rect.BottomRight;break;case ConnectorOrientation.Top:n1 = rect.BottomLeft; n2 = rect.BottomRight;break;case ConnectorOrientation.Right:n1 = rect.TopLeft; n2 = rect.BottomLeft;break;case ConnectorOrientation.Bottom:n1 = rect.TopLeft; n2 = rect.TopRight;break;default:throw new Exception("No opposite corners found!");}}private static void GetNeighborCorners(ConnectorOrientation orientation, Rect rect, out Point n1, out Point n2){switch (orientation){case ConnectorOrientation.Left:n1 = rect.TopLeft; n2 = rect.BottomLeft;break;case ConnectorOrientation.Top:n1 = rect.TopLeft; n2 = rect.TopRight;break;case ConnectorOrientation.Right:n1 = rect.TopRight; n2 = rect.BottomRight;break;case ConnectorOrientation.Bottom:n1 = rect.BottomLeft; n2 = rect.BottomRight;break;default:throw new Exception("No neighour corners found!");}}private static double Distance(Point p1, Point p2){return Point.Subtract(p1, p2).Length;}private static Rect GetRectWithMargin(ConnectorInfo connectorThumb, double margin){Rect rect = new Rect(connectorThumb.DesignerItemLeft,connectorThumb.DesignerItemTop,connectorThumb.DesignerItemSize.Width,connectorThumb.DesignerItemSize.Height);rect.Inflate(margin, margin);return rect;}private static Point GetOffsetPoint(ConnectorInfo connector, Rect rect){Point offsetPoint = new Point();switch (connector.Orientation){case ConnectorOrientation.Left:offsetPoint = new Point(rect.Left, connector.Position.Y);break;case ConnectorOrientation.Top:offsetPoint = new Point(connector.Position.X, rect.Top);break;case ConnectorOrientation.Right:offsetPoint = new Point(rect.Right, connector.Position.Y);break;case ConnectorOrientation.Bottom:offsetPoint = new Point(connector.Position.X, rect.Bottom);break;default:break;}return offsetPoint;}private static void CheckPathEnd(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, List<Point> linePoints){if (showLastLine){Point startPoint = new Point(0, 0);Point endPoint = new Point(0, 0);double marginPath = 15;switch (source.Orientation){case ConnectorOrientation.Left:startPoint = new Point(source.Position.X - marginPath, source.Position.Y);break;case ConnectorOrientation.Top:startPoint = new Point(source.Position.X, source.Position.Y - marginPath);break;case ConnectorOrientation.Right:startPoint = new Point(source.Position.X + marginPath, source.Position.Y);break;case ConnectorOrientation.Bottom:startPoint = new Point(source.Position.X, source.Position.Y + marginPath);break;default:break;}switch (sink.Orientation){case ConnectorOrientation.Left:endPoint = new Point(sink.Position.X - marginPath, sink.Position.Y);break;case ConnectorOrientation.Top:endPoint = new Point(sink.Position.X, sink.Position.Y - marginPath);break;case ConnectorOrientation.Right:endPoint = new Point(sink.Position.X + marginPath, sink.Position.Y);break;case ConnectorOrientation.Bottom:endPoint = new Point(sink.Position.X, sink.Position.Y + marginPath);break;default:break;}linePoints.Insert(0, startPoint);linePoints.Add(endPoint);}else{linePoints.Insert(0, source.Position);linePoints.Add(sink.Position);}}private static ConnectorOrientation GetOpositeOrientation(ConnectorOrientation connectorOrientation){switch (connectorOrientation){case ConnectorOrientation.Left:return ConnectorOrientation.Right;case ConnectorOrientation.Top:return ConnectorOrientation.Bottom;case ConnectorOrientation.Right:return ConnectorOrientation.Left;case ConnectorOrientation.Bottom:return ConnectorOrientation.Top;default:return ConnectorOrientation.Top;}}}
}

27、RubberbandAdorner.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;namespace DiagramDesigner
{public class RubberbandAdorner : Adorner{private Point? startPoint;private Point? endPoint;private Pen rubberbandPen;private DesignerCanvas designerCanvas;public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint): base(designerCanvas){this.designerCanvas = designerCanvas;this.startPoint = dragStartPoint;rubberbandPen = new Pen(Brushes.LightSlateGray, 1);rubberbandPen.DashStyle = new DashStyle(new double[] { 2 }, 1);}protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e){if (e.LeftButton == MouseButtonState.Pressed){if (!this.IsMouseCaptured)this.CaptureMouse();endPoint = e.GetPosition(this);UpdateSelection();this.InvalidateVisual();}else{if (this.IsMouseCaptured) this.ReleaseMouseCapture();}e.Handled = true;}protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e){// release mouse captureif (this.IsMouseCaptured) this.ReleaseMouseCapture();// remove this adorner from adorner layerAdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.designerCanvas);if (adornerLayer != null)adornerLayer.Remove(this);e.Handled = true;}protected override void OnRender(DrawingContext dc){base.OnRender(dc);// without a background the OnMouseMove event would not be fired !// Alternative: implement a Canvas as a child of this adorner, like// the ConnectionAdorner does.dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));if (this.startPoint.HasValue && this.endPoint.HasValue)dc.DrawRectangle(Brushes.Transparent, rubberbandPen, new Rect(this.startPoint.Value, this.endPoint.Value));}private void UpdateSelection(){foreach (ISelectable item in designerCanvas.SelectedItems)item.IsSelected = false;designerCanvas.SelectedItems.Clear();Rect rubberBand = new Rect(startPoint.Value, endPoint.Value);foreach (Control item in designerCanvas.Children){Rect itemRect = VisualTreeHelper.GetDescendantBounds(item);Rect itemBounds = item.TransformToAncestor(designerCanvas).TransformBounds(itemRect);if (rubberBand.Contains(itemBounds) && item is ISelectable){ISelectable selectableItem = item as ISelectable;selectableItem.IsSelected = true;designerCanvas.SelectedItems.Add(selectableItem);}}}}
}

28、Toolbox.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;namespace DiagramDesigner
{// Implements ItemsControl for ToolboxItems    public class Toolbox : ItemsControl{// Defines the ItemHeight and ItemWidth properties of// the WrapPanel used for this Toolboxpublic Size ItemSize{get { return itemSize; }set { itemSize = value; }}private Size itemSize = new Size(50, 50);// Creates or identifies the element that is used to display the given item.        protected override DependencyObject GetContainerForItemOverride(){return new ToolboxItem();}// Determines if the specified item is (or is eligible to be) its own container.        protected override bool IsItemItsOwnContainerOverride(object item){return (item is ToolboxItem);}}
}

29、ToolboxItem.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows;
using System.Windows.Markup;namespace DiagramDesigner
{// Represents a selectable item in the Toolbox--表示工具箱中的可选项/>.public class ToolboxItem : ContentControl{// caches the start point of the drag operation--缓存拖动操作的起点private Point? dragStartPoint = null;static ToolboxItem(){// set the key to reference the style for this control--设置键以引用此控件的样式FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(ToolboxItem), new FrameworkPropertyMetadata(typeof(ToolboxItem)));}protected override void OnPreviewMouseDown(MouseButtonEventArgs e){base.OnPreviewMouseDown(e);this.dragStartPoint = new Point?(e.GetPosition(this));}protected override void OnMouseMove(MouseEventArgs e){base.OnMouseMove(e);if (e.LeftButton != MouseButtonState.Pressed)this.dragStartPoint = null;if (this.dragStartPoint.HasValue){// XamlWriter.Save() has limitations in exactly what is serialized,--XamlWriter.Save()在具体序列化内容方面有限制// see SDK documentation; short term solution only;--见SDK文档;仅短期解决方案string xamlString = XamlWriter.Save(this.Content);DragObject dataObject = new DragObject();dataObject.Xaml = xamlString;WrapPanel panel = VisualTreeHelper.GetParent(this) as WrapPanel;if (panel != null){// desired size for DesignerCanvas is the stretched Toolbox item size--DesignerCanvas所需的大小是拉伸工具箱项的大小double scale = 1.3;dataObject.DesiredSize = new Size(panel.ItemWidth * scale, panel.ItemHeight * scale);}DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Copy);e.Handled = true;}}}// Wraps info of the dragged object into a --将拖动对象的信息包装到类中public class DragObject{// Xaml string that represents the serialized content--Xaml string that represents the serialized contentpublic String Xaml { get; set; }// Defines width and height of the DesignerItem--定义设计器项的宽度和高度// when this DragObject is dropped on the DesignerCanvas--当这个拖拽对象被放到设计画板上时public Size? DesiredSize { get; set; }}
}

30、MainWindow.xaml

<Window x:Class="DiagramDesigner.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:s="clr-namespace:DiagramDesigner"xmlns:c="clr-namespace:DiagramDesigner.Controls"WindowStartupLocation="CenterScreen"SnapsToDevicePixels="True"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Window.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Assets/DesignerItem.xaml"/><ResourceDictionary Source="Assets/ToolboxItem.xaml"/><ResourceDictionary Source="Assets/Toolbox.xaml"/><ResourceDictionary Source="Assets/Connection.xaml"/><ResourceDictionary Source="Assets/Stencils/FlowChartStencils.xaml"/><ResourceDictionary Source="Assets/Stencils/ShapeStencils.xaml"/><ResourceDictionary Source="Assets/Stencils/SymbolStencils.xaml"/></ResourceDictionary.MergedDictionaries></ResourceDictionary></Window.Resources><Grid><Grid Margin="10"><Grid.ColumnDefinitions><ColumnDefinition Width="265"/><ColumnDefinition/></Grid.ColumnDefinitions><!-- Toolbox --><StackPanel Grid.Column="0" Margin="0,0,5,0"><Expander Header="Symbols" Content="{StaticResource SymbolStencils}" IsExpanded="True" /><Expander Header="Flow Chart" Content="{StaticResource FlowChartStencils}" IsExpanded="True"/><Expander Header="Shapes" Content="{StaticResource ShapeStencils}" IsExpanded="False" /></StackPanel><!-- GridSplitter --><GridSplitter Focusable="False" Width="2" Background="{StaticResource LightBorderBrush}"VerticalAlignment="Stretch" HorizontalAlignment="Right"/><!-- Designer --><GroupBox Header="Designer" Grid.Column="1" Margin="3,0,0,0" Background="Transparent"><ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"><s:DesignerCanvas Background="Transparent" Margin="10"/></ScrollViewer></GroupBox></Grid></Grid>
</Window>

31、MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;namespace DiagramDesigner
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13871.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

了解Unity编辑器之组件篇Miscellaneous(九)

一、Aim Constraint&#xff1a;是一种动画约束&#xff0c;用于使一个对象朝向另一个对象或一个指定的矢量方向 Activate按钮&#xff1a;用于激活或停用Aim Constraint。当Aim Constraint处于激活状态时&#xff0c;其约束效果将应用于目标对象。 Zero按钮&#xff1a;用于将…

Zabbix监控ActiveMQ

当我们在线上使用了ActiveMQ 后&#xff0c;我们需要对一些参数进行监控&#xff0c;比如 消息是否有阻塞&#xff0c;哪个消息队列阻塞了&#xff0c;总的消息数是多少等等。下面我们就通过 Zabbix 结合 Python 脚本来实现对 ActiveMQ的监控。 一、创建 Activemq Python 监控…

39. Linux系统下在Qt5.9.9中搭建Android开发环境

1. 说明 QT版本:5.9.9 电脑系统:Linux JDK版本:openjdk-8-jdk SDK版本:r24.4.1 NDK版本:android-ndk-r14b 效果展示: 2. 具体步骤 大致安装的步骤如下:①安装Qt5.9.9,②安装jdk,③安装ndk,④安装sdk,⑤在qt中配置前面安装的环境路径 2.1 安装Qt5.9.9 首先下载…

PHP8的数据类型-PHP8知识详解

在PHP8中&#xff0c;变量不需要事先声明&#xff0c;赋值即声明。 不同的数据类型其实就是所储存数据的不同种类。在PHP8.0、8.1中都有所增加。以下是PHP8的15种数据类型&#xff1a; 1、字符串&#xff08;String&#xff09;&#xff1a;用于存储文本数据&#xff0c;可以使…

VScode的简单使用

一、VScode的安装 Visual Studio Code简称VS Code&#xff0c;是一款跨平台的、免费且开源的现代轻量级代码编辑器&#xff0c;支持几乎主流开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段提示、代码对比等特性&#xff0c;也拥有对git的开箱…

node.js 爬虫图片下载

主程序文件 app.js 运行主程序前需要先安装使用到的模块&#xff1a; npm install superagent --save axios要安装指定版,安装最新版会报错&#xff1a;npm install axios0.19.2 --save const {default: axios} require(axios); const fs require(fs); const superagent r…

STM32 UDS Bootloader开发-上位机篇-CANoe制作(2)

文章目录 前言CANoe增加NodeCAPL脚本获取GUI中的参数刷写过程诊断仪在线接收回调函数发送函数总结前言 在上一篇文章中,介绍了UDS Bootloadaer上位机软件基于CANoe的界面设计。本文继续介绍CAPL脚本的编写以实现刷写过程。 CANoe增加Node 在开始编写CAPL之前,需要在Simula…

Android 耗时分析(adb shell/Studio CPU Profiler/插桩Trace API)

1.adb logcat 查看冷启动时间和Activity显示时间&#xff1a; 过滤Displayed关键字&#xff0c;可看到Activity的显示时间 那上面display后面的是时间是指包含哪些过程的时间呢&#xff1f; 模拟在Application中沉睡1秒操作&#xff0c;冷启动情况下&#xff1a; 从上可知&…

【RTT驱动框架分析01】-pin/gpio驱动分析

0gpio使用测试 LED测试 #define LED1_PIN GET_PIN(C, 1) void led1_thread_entry(void* parameter) {rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);while(1){rt_thread_delay(50); //delay 500msrt_pin_write(LED1_PIN, PIN_HIGH);rt_thread_delay(50); //delay 50…

MySQL之深入InnoDB存储引擎——物理文件

文章目录 一、参数文件二、日志文件三、表结构定义文件四、InnoDB 存储引擎文件1、表空间文件2、重做日志文件 一、参数文件 当 MySQL 实例启动时&#xff0c;数据库会先去读一个配置参数文件&#xff0c;用来寻找数据库的各种文件所在位置以及指定某些初始化参数。在默认情况…

6-Linux的磁盘分区和挂载

Linux的磁盘分区和挂载 Linux分区查看所有设备的挂载情况 将磁盘进行挂载的案例增加一块磁盘的总体步骤1-在虚拟机中增加磁盘2- 分区3-格式化分区4-挂载分区5-进行永久挂载 磁盘情况查询查询系统整体磁盘使用情况查询指定目录的磁盘占用情况 磁盘情况-工作实用指令统计文件夹下…

Vue3搭建启动

Vue3搭建&启动 一、创建项目二、启动项目三、配置项目1、添加编辑器配置文件2、配置别名3、处理sass/scss4、处理tsx(不用的话可以不处理) 四、添加Eslint 一、创建项目 npm create vite 1.project-name 输入项目名vue3-vite 2.select a framework 选择框架 3.select a var…

关于前端框架vue2升级为vue3的相关说明

一些框架需要升级 当前&#xff08;202306&#xff09; Vue 的最新稳定版本是 v3.3.4。Vue 框架升级为最新的3.0版本&#xff0c;涉及的相关依赖变更有&#xff1a; 前提条件&#xff1a;已安装 16.0 或更高版本的Node.js&#xff08;摘&#xff09; 必须的变更&#xff1a;核…

C语言进阶——文件的打开(为什么使用文件、什么是文件、文件的打开和关闭)

目录 为什么使用文件 什么是文件 程序文件 数据文件 文件名 文件的打开和关闭 文件指针 打开和关闭 为什么使用文件 在之前学习通讯录时&#xff0c;我们可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯…

【弹力设计篇】聊聊灾备设计、异地多活设计

单机&集群架构 对于一个高可用系统来说&#xff0c;为了提升系统的稳定性&#xff0c;需要以下常用技术服务拆分、服务冗余、限流降级、高可用架构设计、高可用运维&#xff0c;而本篇主要详细介绍下&#xff0c;高可用架构设计。容灾备份以及同城多活&#xff0c;异地多活…

OpenCV实现高斯模糊加水印

# coding:utf-8 # Email: wangguisendonews.com # Time: 2023/4/21 10:07 # File: utils.pyimport cv2 import PIL from PIL import Image import numpy as np from watermarker.marker import add_mark, im_add_mark import matplotlib.pyplot as plt# PIL Image转换成OpenCV格…

redis分布式锁

Redis 作者继续论述&#xff0c;如果对方认为&#xff0c;发生网络延迟、进程 GC 是在步骤 3 之后&#xff0c;也就是客户端确认拿到了锁&#xff0c;去操作共享资源的途中发生了问题&#xff0c;导致锁失效&#xff0c;那这不止是 Redlock 的问题&#xff0c;任何其它锁服务例…

Flowable-任务-脚本任务

定义 脚本任务&#xff08;Script Task&#xff09;是一种自动执行的活动。当流程执行到达脚本任务时&#xff0c;会执行相应的 脚本&#xff0c;完毕后继续执行后继路线。脚本任务无须人为参与&#xff0c;可以通过定义脚本实现自定义的业务逻辑。 图形标记 脚本任务显示为…

数据结构基础:3.单链表的实现。

单链表的介绍和实现 一.基本概念1.基本结构2.结构体节点的定义&#xff1a; 二.功能接口的实现0.第一个节点&#xff1a;plist1打印链表2创建一个节点3.头插4.头删5.尾插6.尾删7.查找8.在pos之前插入x9.在pos之后插入x10.删除pos位置11.删除pos的后一个位置12.链表释放 三.整体…

C语言每天一练----输出水仙花数

题目&#xff1a;请输出所有的"水仙花数" 题解&#xff1a;所谓"水仙花数"是指一个3位数,其各位数字立方和等于该数本身。 例如, 153是水仙花数, 因为153 1 * 1 * 1 5 * 5 * 5 3 * 3 * 3" #define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h&g…