WPF实现DiagramChart

news/2024/5/20 20:00:49/文章来源:https://blog.csdn.net/qq_27474555/article/details/131912631

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.luyixian.cn/news_show_146834.aspx

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

相关文章

算法通关村第一关-链表白银挑战笔记|公共子节点

两个链表公共子节点问题 提示&#xff1a;大家都在做什么&#xff1f; 不做什么。就是等夏天结束 文章目录 两个链表公共子节点问题前言题目&#xff1a;提供四种解决方法的思路&#xff1a;拿到题目要怎么思考&#xff1a;审题哈希表或集合实现使用栈来实现拼接字符串实现 (组…

短视频矩阵源码开发搭建分享--多账号授权管理

目录 文章目录 前言 一、矩阵号系统是什么&#xff1f; 二、使用步骤 1.创建推广项目 2.多账号授权 3.企业号智能客服系统 总结 前言 短视频多账号矩阵系统&#xff0c;通过多账号一键授权管理的方式&#xff0c;为运营人员打造功能强大及全面的“矩阵式“管理平台。…

从零构建深度学习推理框架-1 简介和Tensor

源代码作者&#xff1a;https://github.com/zjhellofss 本文仅作为个人学习心得领悟 &#xff0c;将原作品提炼&#xff0c;更加适合新手 什么是推理框架&#xff1f; 深度学习推理框架用于对已训练完成的神经网络进行预测&#xff0c;也就是说&#xff0c;能够将深度训练框…

UE虚幻引擎教程_生成云平台指定路径下的exe文件

市面上大量优秀的游戏都是基于UE制作的&#xff0c;UE虚幻引擎制作的作品可以在windows、mac、linux以及ps4、x-boxone、ios、android甚至是html5等平台上运行。本文介绍了UE虚幻引擎如何生成云平台指定路径下的EXE。 一、云平台会运行打包文件夹下指定路径的EXE文件 但有时候…

【多选框、表格全选】element el-checkbox、el-table

话不多说 先看效果&#xff1a; 多选框&#xff1a; 表格全选&#xff1a; <template><div><div class"titleLabel"><div class"lineStyle"></div>统计部门</div><div style"display: flex"><e…

项目开启启动命令整合

启动RabbitMQ管理插件 1.启动 RabbitMQ 管理插件。 rabbitmq-plugins enable rabbitmq_management rabbitmq-server # 直接启动&#xff0c;如果关闭窗⼝或需要在该窗⼝使⽤其他命令时应⽤就会停⽌ rabbitmq-server -detached # 后台启动 rabbitmq-server start # 启⽤服务 rab…

(二)安装部署InfluxDB

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 2 章 安装部署InfluxDB 1、linux 安装方式如下 通过包管理工具安装&#xff0c;比如apt 和yum直接下载可执…

springboot()—— 集成redis

1、新建一个springboot项目 2、添加redis依赖包 可以在新建项目的时候就选上 也可以建完项目以后手动导入pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </d…

2023年基准Kubernetes报告:6个K8s可靠性失误

云计算日益成为组织构建应用程序和服务的首选目的地。尽管一年来经济不确定性的头条新闻主要集中在通货膨胀增长和银行动荡方面&#xff0c;但大多数组织预计今年的云使用和支出将与计划的相同&#xff08;45%&#xff09;&#xff0c;或高于计划的&#xff08;45%&#xff09;…

装饰模式-扩展系统功能

买了新车后&#xff0c;不少人会对车进行装饰&#xff0c;比如给车贴膜&#xff0c;喷上骚粉的漆等。某天&#xff0c;小李和小张都买了辆车&#xff0c;小李想给车贴膜&#xff0c;小张想给车先喷漆然后再贴膜。现在中的做法是&#xff0c;把车开到改装店&#xff0c;如果要喷…

浏览器调试Android App

浏览器调试Android App 1. 背景2. 调试工具3. 手机设置4. 打开浏览器(edge)5. 连接手机6. 点击inspect 开始调试 1. 背景 在工作中经常会遇到在原生app中嵌套h5&#xff0c; 但是在某些需要在app里面调试的内容&#xff0c; 却没有像chrome开发者工具这样的工具来帮助我们快速…

react 在build读取env 数据

默认会读取.env 文件 npm install dotenv --save npm install dotenv-cli --save-dev例如读取.env.test "build:test": "dotenv -e .env.test react-app-rewired build",.env.test REACT_APP_CURRENTMODE devREACT_APP_Public_Path "https://baid…

[NLP]使用Alpaca-Lora基于llama模型进行微调教程

Stanford Alpaca 是在 LLaMA 整个模型上微调&#xff0c;即对预训练模型中的所有参数都进行微调&#xff08;full fine-tuning&#xff09;。但该方法对于硬件成本要求仍然偏高且训练低效。 [NLP]理解大型语言模型高效微调(PEFT) 因此&#xff0c; Alpaca-Lora 则是利用 Lora…

算法竞赛入门【码蹄集新手村600题】(MT1040-1060)

算法竞赛入门【码蹄集新手村600题】(MT1040-1060&#xff09; 目录MT1041 求圆面积和周长MT1042 求矩形的面积和周长MT1043 椭圆计算MT1044 三角形面积MT1045 平行四边形MT1046 菱形MT1047 梯形MT1048 扇形面积MT1049 三角形坐标MT1050 空间三角形MT1051 四边形坐标MT1052 直角…

Java通过URL对象实现简单爬虫功能

目录 一、URL类 1. URL类基本概念 2. 构造器 3. 常用方法 二、爬虫实例 1. 爬取网络图片&#xff08;简易&#xff09; 2. 爬取网页源代码 3. 爬取网站所有图片 一、URL类 1. URL类基本概念 URL&#xff1a;Uniform Resource Locator 统一资源定位符 表示统一资源定位…

day39-Password Strength Background(密码强度背景)

50 天学习 50 个项目 - HTMLCSS and JavaScript day39-Password Strength Background&#xff08;密码强度背景&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name&quo…

Linux 学习记录57(ARM篇)

Linux 学习记录57(ARM篇) 本文目录 Linux 学习记录57(ARM篇)一、外部中断1. 概念2. 流程图框 二、相关寄存器1. GIC CPU Interface (GICC)2. GIC distributor (GICD)3. EXTI registers 三、EXTI 寄存器1. 概述2. 内部框图3. 寄存器功能描述4. EXTI选择框图5. EXTI_EXTICR1 &…

go-zero学习 第六章 分布式事务dtm

go-zero学习 第六章 分布式事务dtm 1 参考文档2 官方示例3 go-zero使用dtm参考代码3.1 go-zero支持dtm 代码操作步骤※3.2 gozerodtm 代码操作步骤 4 注意事项4.1 grpc接口地址※4.2 动态调用过程4.3 dtm的回滚补偿4.4 barrier的空补偿、悬挂等4.5 barrier在rpc中本地事务 1 参…

Volatile关键字详解

Volatile关键字详解 volatile的定义 这个引用JSR中的定义&#xff1a; The Java programming language allows threads to access shared variables (17.1). As a rule, to ensure that shared variables are consistently and reliably updated, a thread should ensure tha…

数据结构【栈和队列】

第三章 栈与队列 一、栈 1.定义&#xff1a;只允许一端进行插入和删除的线性表&#xff0c;结构与手枪的弹夹差不多&#xff0c;可以作为实现递归函数&#xff08;调用和返回都是后进先出&#xff09;调用的一种数据结构&#xff1b; 栈顶&#xff1a;允许插入删除的那端&…