Stencil in WPF Diagram (SfDiagram)
30 Dec 2020 / 24 minutes to read
The Stencil is a gallery of reusable symbols and diagram elements that can be dragged and dropped on the diagram surface many times.
<!--Namespace for stencil-->
xmlns:stencil="clr-namespace:Syncfusion.UI.Xaml.Diagram.Stencil;assembly=Syncfusion.SfDiagram.WPF"
<!--Define a Stencil-->
<stencil:Stencil x:Name="stencil" ExpandMode="All" BorderBrush="Black" BorderThickness="0,0,1,0" />
//Define a Stencil.
Stencil stencil = new Stencil()
{
ExpandMode = ExpandMode.All,
BorderThickness = new Thickness(0,0,1,0),
BorderBrush = new SolidColorBrush(Colors.Black)
};
Add symbols in a Stencil
The Symbol is used to visualize the elements in a Stencil that can be created using the following ways:
- Using the diagram elements.
- Using the SymbolViewModel.
The Stencil’s SymbolSource property is used to define the data source as a collection of objects (symbol, node, connector, and more) that needs to be populated as symbols.
Using the Diagram Elements
The diagram elements such as NodeViewModel, ConnectorViewModel, and GroupViewModel can be used to visualize the symbol.
<!--Initialize the SymbolSource-->
<stencil:Stencil.SymbolSource>
<!--Define the SymbolCollection-->
<local:SymbolCollection>
<syncfusion:NodeViewModel x:Name="node" UnitHeight="70" UnitWidth="100" OffsetX="100" OffsetY="100" Shape="{StaticResource Rectangle}">
</syncfusion:NodeViewModel>
<syncfusion:ConnectorViewModel SourcePoint="100,100" TargetPoint="200,200"/>
<!--Define the DiagramElement- Group-->
<syncfusion:GroupViewModel>
<!--Creates the Groupable Nodes-->
<syncfusion:GroupViewModel.Nodes>
<syncfusion:NodeCollection>
<syncfusion:NodeViewModel UnitHeight="70" ID="srcnode" OffsetX="0" OffsetY="300"
UnitWidth="100"
Shape="{StaticResource Rectangle}">
</syncfusion:NodeViewModel>
<syncfusion:NodeViewModel UnitHeight="70"
ID="tarnode"
OffsetX="100"
OffsetY="500"
UnitWidth="100"
Shape="{StaticResource Rectangle}">
</syncfusion:NodeViewModel>
</syncfusion:NodeCollection>
</syncfusion:GroupViewModel.Nodes>
<!--Creates the Groupable Connectors-->
<syncfusion:GroupViewModel.Connectors>
<syncfusion:ConnectorCollection>
<syncfusion:ConnectorViewModel SourceNodeID="srcnode" TargetNodeID="tarnode"/>
</syncfusion:ConnectorCollection>
</syncfusion:GroupViewModel.Connectors>
</syncfusion:GroupViewModel>
</local:SymbolCollection>
</stencil:Stencil.SymbolSource>
//Define the SymbolSource with SymbolCollection.
stencil.SymbolSource = new SymbolCollection();
//Initialize the diagram element.
NodeViewModel node = new NodeViewModel()
{
UnitHeight = 70,
UnitWidth = 100,
OffsetX = 100, OffsetY = 100,
Shape = App.Current.MainWindow.Resources["Rectangle"],
};
ConnectorViewModel cvm = new ConnectorViewModel()
{
SourcePoint = new Point(100, 100),
TargetPoint = new Point(200, 200),
};
GroupViewModel grp = new GroupViewModel()
{
Nodes = new NodeCollection()
{
new NodeViewModel()
{
ID="srcnode",
UnitHeight=70,
UnitWidth=100,
OffsetX=0,
OffsetY=300,
Shape=App.Current.Resources["Rectangle"]
},
new NodeViewModel()
{
ID="tarnode",
UnitHeight=70,
UnitWidth=100,
OffsetX=100,
OffsetY=500,
Shape=App.Current.Resources["Rectangle"]
}
},
Connectors = new ConnectorCollection()
{
new ConnectorViewModel()
{
SourceNodeID="srcnode",
TargetNodeID="tarnode"
}
}
};
//Adding an element to the collection.
(stencil.SymbolSource as SymbolCollection).Add(node);
(stencil.SymbolSource as SymbolCollection).Add(cvm);
(stencil.SymbolSource as SymbolCollection).Add(grp);
//Adding the ISymbol to the SymbolCollection.
public class SymbolCollection : ObservableCollection<Object>
{
}
Using the SymbolViewModel
The SymbolViewModel has Symbol and SymbolTemplate properties to visualize the Symbol
in the stencil.
<DataTemplate x:Key="Diamond">
<StackPanel>
<Path Stretch="Fill"
Data="M 397.784,287.875L 369.5,316.159L 341.216,287.875L 369.5,259.591L 397.784,287.875 Z"
Fill="White"
Stroke="Black"
StrokeThickness="1" />
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Diamond" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="symboltemplate">
<StackPanel>
<Image Source="/Image/user_image.png" Width="100" Height="80" />
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="User" />
</StackPanel>
</DataTemplate>
<stencil:Stencil.SymbolSource>
<!--Define the SymbolCollection-->
<local:SymbolCollection>
<Syncfusion:SymbolViewModel Symbol="User" SymbolTemplate="{StaticResource symboltemplate}"/>
<Syncfusion:SymbolViewModel Symbol="Diamond" SymbolTemplate="{StaticResource Diamond}"/>
</local:SymbolCollection>
</stencil:Stencil.SymbolSource>
//Define the SymbolSource with the SymbolCollection.
stencil.SymbolSource = new SymbolCollection();
//Initialize the SymbolItem.
SymbolViewModel imagenode = new SymbolViewModel()
{
Symbol = "User",
SymbolTemplate = this.Resources["symboltemplate"] as DataTemplate
};
SymbolViewModel symbol = new SymbolViewModel()
{
Symbol = "Diamond",
SymbolTemplate = this.Resources["Diamond"] as DataTemplate
};
//Adding the element to the collection.
(stencil.SymbolSource as SymbolCollection).Add(imagenode);
(stencil.SymbolSource as SymbolCollection).Add(symbol);
//Adding the ISymbol to the SymbolCollection.
public class SymbolCollection : ObservableCollection<Object>
{
}
Customize the Symbol appearance
You can customize the appearance of a Symbol
by changing its style (Background, BorderThickness, BorderBrush, and Padding). The following code explains how to customize the appearance of the symbol.
The width and height properties of the symbol enable you to define the size of the symbols.
<!--Style for Symbol-->
<Style TargetType="stencil:Symbol">
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="100" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Blue" />
<Setter Property="Padding" Value="5"></Setter>
</Style>
Add the name and tooltip to the symbol
You can use the Name
property of the NodeViewModel, ConnectorViewModel, GroupViewModel, and SymbolViewModel to specify the identifying name to that element. Please find the following code example.
<Stencil:Stencil x:Name="stencil" ExpandMode="ZeroOrMore">
<Stencil:Stencil.SymbolSource>
<Syncfusion:SymbolCollection>
<Syncfusion:NodeViewModel Key="Basic Shapes" UnitHeight="100" UnitWidth="100" Name="Triangle" Shape="{StaticResource Triangle}"></Syncfusion:NodeViewModel>
<Syncfusion:SymbolViewModel Symbol="User" Key="Image" Name="User"
SymbolTemplate="{StaticResource symboltemplate}" />
</Syncfusion:SymbolCollection>
</Stencil:Stencil.SymbolSource>
<Stencil:Stencil.SymbolGroups>
<Stencil:SymbolGroups>
<!--Separate groups based on the key-->
<Stencil:SymbolGroupProvider MappingName="Key" />
</Stencil:SymbolGroups>
</Stencil:Stencil.SymbolGroups>
</Stencil:Stencil>
By default, the Name
property of the diagramming elements(NodeViewModel, ConnectorViewModel, GroupViewModel, and more) is displayed as a tooltip of that symbol while moving the mouse over that symbol but you can give your custom tooltip to that symbol also. Please find the following code example.
<!--Style for Symbol-->
<Style TargetType="stencil:Symbol">
<Setter Property="ToolTip" Value="{Binding Symbol}"></Setter>
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="100" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Blue" />
<Setter Property="Padding" Value="5"></Setter>
</Style>
<Stencil:Stencil x:Name="stencil" ExpandMode="ZeroOrMore">
<Stencil:Stencil.SymbolSource>
<Syncfusion:SymbolCollection>
<Syncfusion:SymbolViewModel Symbol="User" Key="Image" Name="User"
SymbolTemplate="{StaticResource symboltemplate}" />
<Syncfusion:SymbolViewModel Key="Template" Name="Diamond"
SymbolTemplate="{StaticResource Diamond}" >
<Syncfusion:SymbolViewModel.Symbol>
<StackPanel Orientation="Vertical">
<TextBlock FontSize="14" FontWeight="Bold" Foreground="Black" Text="Diamond" Margin="0,0,0,10">
</TextBlock>
<TextBlock FontStyle="Italic" FontSize="12" Foreground="Black" Text="Drag onto the Page">
</TextBlock>
</StackPanel>
</Syncfusion:SymbolViewModel.Symbol>
</Syncfusion:SymbolViewModel>
</Syncfusion:SymbolCollection>
</Stencil:Stencil.SymbolSource>
<Stencil:Stencil.SymbolGroups>
<Stencil:SymbolGroups>
<!--Separate groups based on the key-->
<Stencil:SymbolGroupProvider MappingName="Key" />
</Stencil:SymbolGroups>
</Stencil:Stencil.SymbolGroups>
</Stencil:Stencil>
NOTE
The
DataContext
of theSymbol
will be any diagramming elements such asNodeViewModel,
ConnectorViewModel,
GroupViewModel,
andSymbolViewModel.
Group symbols into a category
The symbols of the same category can be grouped using the SymbolGroupProvider. The SymbolGroupProvider
groups based on the MappingName property, which has the name of the property whose value will be in the group category. In the following code example, the MappingName
has a value of “Key” and the SymbolGroupProvider
will create the group based on the value of the Key
property. The symbols with the same category name could be grouped under that category.
<Style TargetType="sync:Node">
<Setter Property="ShapeStyle">
<Setter.Value>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FF5B9BD5"></Setter>
<Setter Property="Stretch" Value="Fill"></Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="sync:Connector">
<Setter Property="ConnectorGeometryStyle">
<Setter.Value>
<Style TargetType="Path">
<Setter Property="Stroke" Value="#FF5B9BD5"></Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="TitleTemplate">
<TextBlock x:Name="HeaderText" Text="{Binding}" FontSize="15" FontWeight="SemiBold" Foreground="#2b579a" />
</DataTemplate>
<stencil:Stencil Grid.Column="0" BorderThickness="1" Title="Shapes" TitleTemplate="{StaticResource TitleTemplate}" BorderBrush="#dfdfdf" x:Name="stencil">
<!--Initialize the SymbolSource-->
<stencil:Stencil.SymbolSource>
<!--Define the SymbolCollection-->
<local:SymbolCollection>
<syncfusion:NodeViewModel x:Name="node" UnitHeight="70" UnitWidth="100" OffsetX="100" OffsetY="100" Shape="{StaticResource Rectangle}" Key="Node">
</syncfusion:NodeViewModel>
<syncfusion:ConnectorViewModel SourcePoint="100,100" TargetPoint="200,200" Key="Connector"/>
<!--Define the DiagramElement- Group-->
<syncfusion:GroupViewModel Key="Group">
<!--Creates the Groupable Nodes-->
<syncfusion:GroupViewModel.Nodes>
<syncfusion:NodeCollection>
<syncfusion:NodeViewModel UnitHeight="70" ID="srcnode" OffsetX="0" OffsetY="300"
UnitWidth="100"
Shape="{StaticResource Rectangle}">
</syncfusion:NodeViewModel>
<syncfusion:NodeViewModel UnitHeight="70"
ID="tarnode"
OffsetX="100"
OffsetY="500"
UnitWidth="100"
Shape="{StaticResource Rectangle}">
</syncfusion:NodeViewModel>
</syncfusion:NodeCollection>
</syncfusion:GroupViewModel.Nodes>
<!--Creates the Groupable Connectors-->
<syncfusion:GroupViewModel.Connectors>
<syncfusion:ConnectorCollection>
<syncfusion:ConnectorViewModel SourceNodeID="srcnode" TargetNodeID="tarnode"/>
</syncfusion:ConnectorCollection>
</syncfusion:GroupViewModel.Connectors>
</syncfusion:GroupViewModel>
</local:SymbolCollection>
</stencil:Stencil.SymbolSource>
<!--Initialize the SymbolGroup-->
<stencil:Stencil.SymbolGroups>
<stencil:SymbolGroups>
<!--Map Symbols Using MappingName-->
<stencil:SymbolGroupProvider MappingName="Key">
</stencil:SymbolGroupProvider>
</stencil:SymbolGroups>
</stencil:Stencil.SymbolGroups>
</stencil:Stencil>
//Define a Stencil.
Stencil stencil = new Stencil()
{
ExpandMode =ExpandMode.All,
BorderThickness =new Thickness(0,0,1,0),
BorderBrush =new SolidColorBrush(Colors.Black)
};
//Define the SymbolSource with the SymbolCollection.
stencil.SymbolSource = new SymbolCollection();
NodeViewModel node = new NodeViewModel()
{
UnitHeight = 100,
UnitWidth = 100,
OffsetX = 100, OffsetY = 100,
Shape = App.Current.MainWindow.Resources["Rectangle"],
Key = "Node"
};
ConnectorViewModel cvm = new ConnectorViewModel()
{
SourcePoint = new Point(100, 100),
TargetPoint = new Point(200, 200),
Key="Connector"
};
GroupViewModel grp = new GroupViewModel()
{
Key="Group",
Nodes = new NodeCollection()
{
new NodeViewModel()
{
ID="srcnode",
UnitHeight=70,
UnitWidth=100,
OffsetX=0,
OffsetY=300,
Shape=App.Current.Resources["Rectangle"]
},
new NodeViewModel()
{
ID="tarnode",
UnitHeight=70,
UnitWidth=100,
OffsetX=100,
OffsetY=500,
Shape=App.Current.Resources["Rectangle"]
}
},
Connectors = new ConnectorCollection()
{
new ConnectorViewModel()
{
SourceNodeID="srcnode",
TargetNodeID="tarnode"
}
}
};
//Add the element to the symbol collection.
(stencil.SymbolSource as SymbolCollection).Add(node);
(stencil.SymbolSource as SymbolCollection).Add(cvm);
(stencil.SymbolSource as SymbolCollection).Add(grp);
//Define the SymbolGroups.
stencil.SymbolGroups = new SymbolGroups()
{
new SymbolGroupProvider()
{
MappingName = "Key"
}
};
Customize the appearance of the symbol group header
You can customize the appearance of a SymbolGroup
header by changing its style. The following code explains how to customize the appearance of the symbol group header.
<!--Style for Symbol Group-->
<Style TargetType="stencil:SymbolGroup">
<Setter Property="FontFamily" Value="Regular"/>
<Setter Property="Background" Value="#ffffff"/>
<Setter Property="Foreground" Value="#222222"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<stencil:Header>
<stencil:Header.Template>
<ControlTemplate TargetType="stencil:Header">
<Grid>
<Border x:Name="header" Background="#f5f5f5" BorderBrush="#dfdfdf" BorderThickness="1">
<ContentPresenter Margin="10" Content="{Binding}"/>
</Border>
</Grid>
</ControlTemplate>
</stencil:Header.Template>
</stencil:Header>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Expand and collapse the symbol group
When there is more number of symbol groups in the stencil then you can expand and collapse the symbol groups using the ExpandMode property of Stencil.
The ExpandMode
property allows you to decide the number of symbol groups that can be expanded in a stencil.
ExpandMode | Description |
---|---|
All | Enables or disables all the symbol group that can be expanded |
One | Enables or disables only one symbol group that can be expanded |
OneOrMore | Enables or disables one or more symbol group that can be expanded |
ZeroOrMore | Enables or disables none or more symbol group that can be expanded |
ZeroOrOne | Enables or disables none or one symbol group that can be expanded |
Symbol categories
There are plenty of shapes available in the diagram resource dictionary. It takes more time and allows repeated code samples to add all symbols to the stencil. To avoid this, the shapes are split and categorized as a list of symbols in the StencilCategory class. You can add more than one category using the Categories property of the stencil class.
The Categories
can be mentioned by using the following properties of the StencilCategory
class,
- Keys: Specifies the static resource key name value of the category collection.
- Title: Specifies the title that should be displayed as a header of the category collection.
Built-in symbol categories
The built-in shape paths available in the diagram resource dictionary are grouped by categories. The following are the built-in categories being available in the diagram resource dictionary:
- BasicShapes
- FlowShapes
- ArrowShapes
- DataFlowShapes
- UMLActivity
- UMLUseCase
- UMLRelationship
- ElectricalShapes
- SwimlaneShapes
- BPMNEditorShapes
<!--Initialize the stencil-->
<Stencil:Stencil x:Name="stencil" Title="Shapes" TitleTemplate="{StaticResource TitleTemplate}"
ExpandMode="ZeroOrMore" BorderBrush="#dfdfdf" BorderThickness="1">
<!--Initialize the stencil categories-->
<Stencil:Stencil.Categories>
<Stencil:StencilCategoryCollection>
<!--Specify the basic shapes category with title and resource key-->
<Stencil:StencilCategory Title="Basic Shapes" Keys="{StaticResource BasicShapes}"/>
</Stencil:StencilCategoryCollection>
</Stencil:Stencil.Categories>
<Stencil:Stencil.SymbolGroups>
<Stencil:SymbolGroups>
<!--Separate groups based on the key-->
<Stencil:SymbolGroupProvider MappingName="Key" />
</Stencil:SymbolGroups>
</Stencil:Stencil.SymbolGroups>
</Stencil:Stencil>
Add the custom shapes categories
The custom symbol collections can be added to the stencil by defining the custom symbol’s resource collection.
<!--custom path data-->
<sys:String x:Key="CustomPath">
F1M1.66,0.25C0.882,0.25,0.25,0.881,0.25,1.66L0.25,24.622C0.25,25.401,0.882,26.032,1.66,26.032L4.48,26.032C5.259,26.032,5.89,25.401,5.89,24.622L5.89,1.66C5.89,0.881,5.259,0.25,4.48,0.25z
</sys:String>
<!--custom shapes collection-->
<x:Array Type="sys:String" x:Key="customShapeCollection">
<sys:String>Rectangle</sys:String>
<sys:String>Cube</sys:String>
<sys:String>Triangle</sys:String>
<sys:String>Ellipse</sys:String>
<sys:String>CustomPath</sys:String>
</x:Array>
<DataTemplate x:Key="TitleTemplate">
<TextBlock x:Name="HeaderText" Text="{Binding}" FontSize="15" FontWeight="SemiBold" Foreground="#2b579a" >
</TextBlock>
</DataTemplate>
<!--Initialize the stencil-->
<Stencil:Stencil x:Name="stencil" Title="Shapes" TitleTemplate="{StaticResource TitleTemplate}" ExpandMode="ZeroOrMore"
BorderBrush="#dfdfdf" BorderThickness="1">
<!--Initialize the stencil categories-->
<Stencil:Stencil.Categories>
<Stencil:StencilCategoryCollection>
<!--Specify the custom shapes category with title and resource key-->
<Stencil:StencilCategory Title="Custom shapes" Keys="{StaticResource customShapeCollection}"/>
</Stencil:StencilCategoryCollection>
</Stencil:Stencil.Categories>
<Stencil:Stencil.SymbolGroups>
<Stencil:SymbolGroups>
<!--Separate groups based on the key-->
<Stencil:SymbolGroupProvider MappingName="Key" />
</Stencil:SymbolGroups>
</Stencil:Stencil.SymbolGroups>
</Stencil:Stencil>
NOTE
The custom symbol collections should be added in the App.xaml file.
Customize the appearance of the symbols in the built-in categories
The built-in symbol categories symbol sizes are equivalent to the Visio symbol size. Each symbol available in the category collection can be customized by the PrepareSymbolViewModel virtual method of the stencil class. Symbols can be modified by using the following properties of the PrepareSymbolViewModel
method,
-
Item
: To modify the symbol and its properties. -
SymbolName
: To know the name of the symbol. -
CategoryName
: To know the name of the category.
Also, you can decide whether a symbol can be added to the stencil symbol collection or not. It can be achieved by using the Cancel
property of CanAddSymbol the virtual method of stencil class.
/// <summary>
/// The custom class for the stencil view model.
/// </summary>
public class StencilViewModel : Stencil
{
/// <summary>
/// Overridden method to change the symbol.
/// </summary>
/// <param name="Item">Item value of the shape</param>
/// <param name="SymbolName">Name of the symbol</param>
/// <param name="CategoryName">Name of the category</param>
/// <returns>Return the item of the shape</returns>
protected override object PrepareSymbolViewModel(object Item, string SymbolName, string CategoryName)
{
if (SymbolName == "Rectangle")
{
(Item as INode).UnitWidth = 80;
(Item as INode).UnitHeight = 40;
return Item;
}
else
return base.PrepareSymbolViewModel(Item, SymbolName, CategoryName);
}
/// <summary>
/// Overidden method to decide whether a symbol can be added or not
/// </summary>
/// <param name="symbolName">Name of the symbol</param>
/// <param name="categoryName">Name of the category</param>
/// <returns>Return the boolean</returns>
protected override bool CanAddSymbol(string symbolName, string categoryName)
{
if (symbolName == "Triangle")
{
return false;
}
return base.CanAddSymbol(symbolName, categoryName);
}
}
Filter the symbols based on groups/category
The grouped symbols can be filtered or hide using the SymbolFilters. The SymbolFilters
are a collection of SymbolFilterProvider which contains the SymbolFilter delegate property to filter the specific symbol group.
The Content and ContentTemplate property of the SymbolFilterProvider
is used to update the content of the symbol filter.
The following code explains how to create a symbol filter in the stencil.
<Window.DataContext>
<viewmodel:StencilVM></viewmodel:StencilVM>
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="TitleTemplate">
<TextBlock x:Name="HeaderText" Text="{Binding}" FontSize="15" FontWeight="SemiBold" Foreground="#2b579a" >
</TextBlock>
</DataTemplate>
<!--Style for Node-->
<Style TargetType="{x:Type syncfusion:Node}">
<Setter Property="ShapeStyle">
<Setter.Value>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FF5B9BD5"/>
<Setter Property="Stroke" Value="#FFEDF1F6"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="Stretch" Value="Fill"/>
</Style>
</Setter.Value>
</Setter>
</Style>
<!--Style for Connector-->
<Style TargetType="{x:Type syncfusion:Connector}">
<Setter Property="ConnectorGeometryStyle">
<Setter.Value>
<Style TargetType="Path">
<Setter Property="Stroke" Value="#FF5B9BD5"></Setter>
<Setter Property="StrokeThickness" Value="1"></Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="TargetDecoratorStyle">
<Setter.Value>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FF5B9BD5"></Setter>
<Setter Property="StrokeThickness" Value="1"></Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
<!--Style for Symbol-->
<Style TargetType="stencil:Symbol">
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="100" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Margin" Value="4"></Setter>
</Style>
<!--Style for Symbol Group-->
<Style TargetType="stencil:SymbolGroup">
<Setter Property="FontFamily" Value="Regular"/>
<Setter Property="Background" Value="#ffffff"/>
<Setter Property="Foreground" Value="#222222"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<stencil:Header>
<stencil:Header.Template>
<ControlTemplate TargetType="stencil:Header">
<Grid>
<Border x:Name="header" Background="#f5f5f5" BorderBrush="#dfdfdf" BorderThickness="1">
<ContentPresenter Margin="10" Content="{Binding}"/>
</Border>
</Grid>
</ControlTemplate>
</stencil:Header.Template>
</stencil:Header>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="8*"/>
</Grid.ColumnDefinitions>
<!--Define the Stencil-->
<stencil:Stencil Grid.Column="0" BorderThickness="1" BorderBrush="#dfdfdf" Title="Shapes" TitleTemplate="{StaticResource TitleTemplate}" x:Name="stencil" ExpandMode="All" SymbolFilters="{Binding Symbolfilters}" SelectedFilter="{Binding Selectedfilter}">
<!--Initialize the SymbolSource-->
<stencil:Stencil.SymbolSource>
<!--Initialize the SymbolCollection-->
<local:SymbolCollection>
<!--Define the DiagramElement-Node-->
<syncfusion:NodeViewModel x:Name="node" UnitHeight="100" UnitWidth="100" OffsetX="100" OffsetY="100" Shape="{StaticResource Rectangle}" Key="Nodes">
</syncfusion:NodeViewModel>
<!--Define the DiagramElement- Connector-->
<syncfusion:ConnectorViewModel SourcePoint="100,100" TargetPoint="200,200" Key="Connector">
</syncfusion:ConnectorViewModel>
</local:SymbolCollection>
</stencil:Stencil.SymbolSource>
<!--Initialize the SymbolGroup-->
<stencil:Stencil.SymbolGroups>
<stencil:SymbolGroups>
<!--Map Symbols Using MappingName-->
<stencil:SymbolGroupProvider MappingName="Key"></stencil:SymbolGroupProvider>
</stencil:SymbolGroups>
</stencil:Stencil.SymbolGroups>
</stencil:Stencil>
</Grid>
public class StencilVM : INotifyPropertyChanged
{
public StencilVM()
{
Symbolfilters = new SymbolFilters();
SymbolFilterProvider all = new SymbolFilterProvider { Content = "All", SymbolFilter = Filter };
SymbolFilterProvider Node = new SymbolFilterProvider { Content = "Nodes", SymbolFilter = Filter };
SymbolFilterProvider Con = new SymbolFilterProvider { Content = "Connector", SymbolFilter = Filter };
this.Symbolfilters.Add(all);
this.Symbolfilters.Add(Node);
this.Symbolfilters.Add(Con);
this.Selectedfilter = Symbolfilters[0];
}
// Define the filtering of symbols.
private bool Filter(SymbolFilterProvider sender, object symbol)
{
if (symbol is NodeViewModel)
{
if (sender.Content.ToString() == (symbol as NodeViewModel).Key.ToString())
return true;
}
if (symbol is ConnectorViewModel)
{
if (sender.Content.ToString() == (symbol as ConnectorViewModel).Key.ToString())
return true;
}
if (sender.Content.ToString() == "All")
{
return true;
}
return false;
}
public ObservableCollection<SymbolFilterProvider> Symbolfilters { get; set; }
public SymbolFilterProvider Selectedfilter { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
Appearance of symbol filters
The visual appearance of the symbol filters can be customized to either a combo box or list view. The SymbolFilterDisplayMode property of the Stencil
is used to customize the appearance of the symbol filter.
SymbolFilterDisplayMode | Description |
---|---|
ComboBox | The symbol filter is visually represented in a combo box. |
List | The symbol filter are visually represented in a listview |
In List
display mode, the filters will be added in the list view only when you set the IsChecked property of the SymbolFilterProvider
to true.
You can dynamically add or remove the filter from the list view, by clicking the more shapes option and checked or unchecked the filter to add or remove that filter from the list view. Check marks indicate the filters added to the List.
SelectedFilter
There can be multiple SymbolFilters but only one filter can be selected at a time. You can select the filter from the collection of filters using the SelectedFilter of the stencil. In the combo box, a particular item will be selected and updated that item to the SelectedFilter. In List view, the selected item will be updated as a SelectedFilter.
Add a title to the Stencil
The Title property of the Stencil
is used to add the title to the stencil. Please find the following code example that explains how to provide the content to the stencil.
<!--Initialize the stencil-->
<Stencil:Stencil x:Name="stencil" Title="Shapes">
<!--Initialize the stencil categories-->
<Stencil:Stencil.Categories>
<Stencil:StencilCategoryCollection>
<!--Specify the basic shapes category with a title and resource key-->
<Stencil:StencilCategory Title="Basic Shapes" Keys="{StaticResource BasicShapes}"/>
</Stencil:StencilCategoryCollection>
</Stencil:Stencil.Categories>
</Stencil:Stencil>
Customize Stencil title
The appearance of the title can be customized by using the TitleTemplate property of the Stencil.
Please find the code example that explains how to add a title and its customization.
<DataTemplate x:Key="TitleTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="/Image/Shapes.png"
Width="15" Height="15" />
<TextBlock Margin="5,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Shapes" />
</StackPanel>
</DataTemplate>
<!--Initialize the stencil-->
<Stencil:Stencil x:Name="stencil" Title="Shapes" TitleTemplate="{StaticResource TitleTemplate}>
<!--Initialize the stencil categories-->
<Stencil:Stencil.Categories>
<Stencil:StencilCategoryCollection>
<!--Specify the basic shapes category with a title and resource key-->
<Stencil:StencilCategory Title="Basic Shapes" Keys="{StaticResource BasicShapes}"/>
</Stencil:StencilCategoryCollection>
</Stencil:Stencil.Categories>
</Stencil:Stencil>
Browse the symbols from the stencil
You can search for symbols in the stencil by entering the symbol name (e.g: “rectangle”) in the search text box and start searching. The symbols are resulted by matching the value of the Name
property with the string entered in the search textbox. The ShowSearchTextBox property of the Stencil
is used to show or hide the search textbox in a stencil.
The following image shows the search result of the symbol.
Stencil display mode
The Stencil view can be toggled between the expanded and compact modes by clicking the expander at the top right corner of the Stencil during run-time. You can do the same using the DisplayMode property of the Stencil.
DisplayMode | Description |
---|---|
Compact | The stencil always shows as a narrow sliver which can be opened to full width |
Expanded | Specifies to update the Expanded state of the stencil |
You can show or hide the expander icon by using the ShowDisplayModeToggleButton property of the Stencil.
Preview for Drag and Drop
When you drag an item from the Stencil to the diagram, a preview of the dragged item will be displayed. Preview of the item can be enabled or disabled by using the StencilConstraints ShowPreview.
//Enables the drag and drop preview.
stencil.Constraints = stencil.Constraints | StencilConstraints.ShowPreview;
//Disables the drag and drop preview.
stencil.Constraints = stencil.Constraints & ~StencilConstraints.ShowPreview;
Here, the stencil is an instance of Stencil.
Customization of Preview for drag and drop
You can customize the preview content by overriding the PrepareDragDropPreview method of the Stencil. You can define your customized preview to the SymbolPreview property of the stencil.
public class CustomStencil : Stencil
{
//Virtual method to customize the preview of dragging the symbol from a stencil.
protected override void PrepareDragDropPreview()
{
this.SymbolPreview = new ContentPresenter()
{
Content = new Rectangle()
{
Width = 50,
Height = 50,
Fill = new SolidColorBrush(Colors.SteelBlue)
}
};
}
}
Events
-
The
Expanded Event
andCollapsed Event
are notified to provide interactions in the SymbolGroup. To explore about arguments, refer to the SymbolGroupExpandCollapseEventArgs - The
DragEnter Event
notifies when an element enters into the diagram from a stencil. - The
DragLeave Event
notifies when an element leaves from the diagram. - The
DragOver Event
notifies when an element drag over another diagram element. - The
ItemDropEvent Event
notifies when an element is dropped on the diagram.
To explore about arguments, refer to the ItemDropEventArgs
Restrict the node dropped on Diagram
The diagram provides support to cancel the drag and drop operation from the stencil to the diagram in two ways.
-
Using the
Cancel
argument ofItemDropEventArgs
. For example, if you need to restrict drop for a particular node or based on some condition, then this argument will allow you to achieve the same. To explore about arguments, refer to the ItemDropEventArgs. -
When the ESC key is pressed.
Symbol dragging outside diagram bounds
By default, the cursor appears as a block cursor when dragging the symbol (from stencil) outside the diagram bounds. The SfDiagram provides supports to drag the elements within the given limitations. For details, please refer to the Dragging based on DragLimit
Preserving the node template when drag and drop
The SfDiagram using the serialization and deserialization approach for drag and drop the element from a stencil and it did not serialize the framework properties like the Content and ContentTemplate properties. So, you need to retain templates as a resource and reassign them once it loaded back in the diagram. This can be achieved by using the ItemAdded event to restore the Content and ContentTemplate property values.
private void MainWindow_ItemAdded(object sender, ItemAddedEventArgs args)
{
if(args.Item is CustomNode)
{
CustomNode node = args.Item as CustomNode;
node.Content = node.CustomContent;
node.ContentTemplate = App.Current.MainWindow.Resources[node.CustomContentTemplate] asDataTemplate;
}
}
Constraints
The Constraints
property of stencil allows you to enable or disable certain features. For more information about stencil constraints, refer to the StencilConstraints.
See Also
- How to drag and drop elements from a treeview ?
- How to refresh the stencil when adding a new symbol in the symbol source ?
- How to host different UI elements as a node content ?
- How to notify stencil has been loaded ?
- How to expand all SymbolGroups ?
- How to get the base node interface while dropping a Symbol from Stencil to SfDiagram ?
- How to use different User Controls into Stencil?