<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.2" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>ILOG .NET Visualization Blog &#187; Diagram</title>
	<link>http://blogs.ilog.com/netvisu</link>
	<description>Postings from the Visualization .NET Development Team</description>
	<pubDate>Fri, 28 Nov 2008 13:39:40 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.2</generator>
	<language>en</language>
			<item>
		<title>A Silverlight GUI for Google Analytics</title>
		<link>http://blogs.ilog.com/netvisu/2008/11/28/a-silverlight-gui-for-google-analytics/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/11/28/a-silverlight-gui-for-google-analytics/#comments</comments>
		<pubDate>Fri, 28 Nov 2008 13:39:40 +0000</pubDate>
		<dc:creator>Eric Durocher</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Silverlight]]></category>

		<category><![CDATA[analytics]]></category>

		<category><![CDATA[graph layout]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/11/28/a-silverlight-gui-for-google-analytics/</guid>
		<description><![CDATA[Continuing our series of posts on Silverlight experiments, here is a sample that you can use to view real-life data if you use <a href="http://www.google.com/analytics/index.html" target="_blank">Google Analytics</a> to monitor your web site traffic.

The application first asks you to login using your Google&#8230;]]></description>
			<content:encoded><![CDATA[<p>Continuing our series of posts on Silverlight experiments, here is a sample that you can use to view real-life data if you use <a href="http://www.google.com/analytics/index.html" target="_blank">Google Analytics</a> to monitor your web site traffic.</p>
<p>The application first asks you to login using your Google Analytics  email/password (the login screen uses the new AutoCompleteBox and PasswordBox controls from the <a href="http://www.codeplex.com/Silverlight" target="_blank">Silverlight Toolkit</a>). Then, you can select the account to use and the web site to analyze. You can also choose the start and end dates of the report, and filter the web pages according to a minimum number of page views. When you click Load, the application sends HTTP requests to Google Analytics and receives an XML report containing the traffic data for your web site.</p>
<p>Then, the application displays a diagram that shows the hierarchy of your web pages. The size of the nodes reflects the number of page views, so you can see what areas of your site are most visited. Like in the <a href="http://blogs.ilog.com/netvisu/2008/10/09/silverlight-experimentations-from-the-net-visu-lab-part-4/" target="_blank">Org Chart</a>,the diagram is arranged by a tree layout algorithm, and you can zoom and pan, select a page to view its details, expand/collapse branches, etc.</p>
<p>Have fun!</p>
<p><strong><a href="http://svdemo02.ilog.com/GoogleAnalytics/GoogleAnalytics.html">START THE DEMO</a></strong></p>
<p><a href="http://svdemo02.ilog.com/GoogleAnalytics/GoogleAnalytics.html" title="ga.png"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/11/ga.png" alt="ga.png" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/11/28/a-silverlight-gui-for-google-analytics/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Silverlight experimentations from the .NET Visu Lab (Part 4)</title>
		<link>http://blogs.ilog.com/netvisu/2008/10/09/silverlight-experimentations-from-the-net-visu-lab-part-4/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/10/09/silverlight-experimentations-from-the-net-visu-lab-part-4/#comments</comments>
		<pubDate>Thu, 09 Oct 2008 12:35:18 +0000</pubDate>
		<dc:creator>Eric Durocher</dc:creator>
		
		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Silverlight]]></category>

		<category><![CDATA[graph layout]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/10/09/silverlight-experimentations-from-the-net-visu-lab-part-4/</guid>
		<description><![CDATA[Here is yet another Silverlight experiment: an Organization Chart sample, similar to the <a href="http://visudemos.ilog.com/webdemos/orgchart/orgchart.html">ILOG Elixir Organization Chart</a> component.

This new sample uses the same Diagram control as the one used in <a href="http://blogs.ilog.com/netvisu/2008/10/06/silverlight-experiments-from-our-net-visu-lab-part-2">this post</a>, but it uses a tree layout algorithm instead&#8230;]]></description>
			<content:encoded><![CDATA[<p>Here is yet another Silverlight experiment: an Organization Chart sample, similar to the <a href="http://visudemos.ilog.com/webdemos/orgchart/orgchart.html">ILOG Elixir Organization Chart</a> component.</p>
<p>This new sample uses the same Diagram control as the one used in <a href="http://blogs.ilog.com/netvisu/2008/10/06/silverlight-experiments-from-our-net-visu-lab-part-2">this post</a>, but it uses a tree layout algorithm instead of a hierarchical layout. The Diagram control offers several other layout algorithms, and each algorithm has tons of options to fit a large range of application.</p>
<p>Some of the things to note in this demo:</p>
<ul>
<li>Each branch of the tree can be collapsed and re-expanded by double-clicking the parent node (you can also use the tree view on the left to collapse/expand).</li>
<li>When you zoom in (using the mouse wheel for example), more details appear in each node, and these details disappear again when you zoom out. This gives a clearer view at small zoom levels.</li>
</ul>
<p><strike>To run the demo you will need the Silverlight2 beta 2 plugin</strike>.</p>
<p>UPDATE: the demo has been updated to use the final release of Silverlight 2.</p>
<p><strong><a href="http://svdemo02.ilog.com/SilverlightOrgChart/OrgChart.html">START THE DEMO</a></strong></p>
<p><strong>Overview</strong><br />
<a href="http://svdemo02.ilog.com/SilverlightOrgChart/OrgChart.html" title="Silverlight Org Chart"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/10/orgchart.png" alt="Silverlight Org Chart" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/10/09/silverlight-experimentations-from-the-net-visu-lab-part-4/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Silverlight experiments from our .NET Visu Lab (Part 2)</title>
		<link>http://blogs.ilog.com/netvisu/2008/10/06/silverlight-experiments-from-our-net-visu-lab-part-2/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/10/06/silverlight-experiments-from-our-net-visu-lab-part-2/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 09:16:35 +0000</pubDate>
		<dc:creator>Emmanuel Tissandier</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Silverlight]]></category>

		<category><![CDATA[Microsoft Project]]></category>

		<category><![CDATA[Xml]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/10/06/silverlight-experiments-from-our-net-visu-lab-part-2/</guid>
		<description><![CDATA[In a <a href="http://blogs.ilog.com/netvisu/2008/10/01/silverlight-experiments-from-our-net-visu-lab-part-1/">previous post</a> I showed a first Silverlight experimentation displaying a project plan in a <a href="http://blogs.ilog.com/netvisu/2008/10/01/silverlight-experiments-from-our-net-visu-lab-part-1/">Silverlight Gantt Chart control</a>. Here is a second experimentation on the same topic. This small example also displays a project plan but this time the&#8230;]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://blogs.ilog.com/netvisu/2008/10/01/silverlight-experiments-from-our-net-visu-lab-part-1/">previous post</a> I showed a first Silverlight experimentation displaying a project plan in a <a href="http://blogs.ilog.com/netvisu/2008/10/01/silverlight-experiments-from-our-net-visu-lab-part-1/">Silverlight Gantt Chart control</a>. Here is a second experimentation on the same topic. This small example also displays a project plan but this time the plan is displayed as a graph. If you have read the post I wrote about <a href="http://blogs.ilog.com/netvisu/2008/05/19/displaying-a-microsoft-project-xml-file-using-diagrammer-for-net-wpf-and-linq-part-1/">displaying a Microsoft Project XML file using WPF</a>, you have an idea about the way this Silverlight sample is build since this is exactly the same idea. An experimental Silverlight Diagram control is used to represent the graph, where nodes are representing tasks and links are representing the predecessor constraints between tasks. The Diagram control automatically does the layout of the graph with a hierarchical layout algorithm that represents nicely the flow of tasks in the project plan.</p>
<p><strong><a href="http://svdemo02.ilog.com/SilverlightCriticalPath/CriticalPath.html">START THE DEMO</a></strong> </p>
<p><strong>Overview</strong></p>
<p><strong><a href="http://svdemo02.ilog.com/SilverlightCriticalPath/CriticalPath.html"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/10/criticalpath.png" alt="Start the sample" /></a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/10/06/silverlight-experiments-from-our-net-visu-lab-part-2/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Selected User Meeting Presentations: A (French) Film Festival</title>
		<link>http://blogs.ilog.com/netvisu/2008/08/25/selected-user-meeting-presentations-a-french-film-festival/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/08/25/selected-user-meeting-presentations-a-french-film-festival/#comments</comments>
		<pubDate>Mon, 25 Aug 2008 08:19:51 +0000</pubDate>
		<dc:creator>Emmanuel Tissandier</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Ajax]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Visual Studio]]></category>

		<category><![CDATA[WPF]]></category>

		<category><![CDATA[Adobe]]></category>

		<category><![CDATA[Diagrammer for .NET]]></category>

		<category><![CDATA[Microsoft]]></category>

		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/08/25/selected-user-meeting-presentations-a-french-film-festival/</guid>
		<description><![CDATA[Ed Kiraly has posted in the JViews blog a <a href="http://blogs.ilog.com/jviews/2008/08/22/selected-user-meeting-presentations-a-french-film-festival/">series of videos </a>recorded during a user group meeting in Paris. The recorded sessions (in French) are from our CEO, from the Visualization product team and from Microsoft and Adobe. You will find here a&#8230;]]></description>
			<content:encoded><![CDATA[<p>Ed Kiraly has posted in the JViews blog a <a href="http://blogs.ilog.com/jviews/2008/08/22/selected-user-meeting-presentations-a-french-film-festival/">series of videos </a>recorded during a user group meeting in Paris. The recorded sessions (in French) are from our CEO, from the Visualization product team and from Microsoft and Adobe. You will find here a video showing how a easily create a graph display using WPF and Diagrammer for .NET.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/08/25/selected-user-meeting-presentations-a-french-film-festival/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Adding Icons to a Link</title>
		<link>http://blogs.ilog.com/netvisu/2008/08/13/adding-icons-to-a-link/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/08/13/adding-icons-to-a-link/#comments</comments>
		<pubDate>Wed, 13 Aug 2008 13:27:11 +0000</pubDate>
		<dc:creator>Eric Durocher</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[icon]]></category>

		<category><![CDATA[link]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/08/13/adding-icons-to-a-link/</guid>
		<description><![CDATA[The <a href="http://www.ilog.fr/products/diagrammernet/documentation/html/ILOGDiagrammerClassLibrary/html/T_ILOG_Diagrammer_Graphic_Link.htm">Link</a> object in ILOG Diagrammer for .NET lets you easily add text items at any position on the link path (using the <a href="http://www.ilog.fr/products/diagrammernet/documentation/html/ILOGDiagrammerClassLibrary/html/P_ILOG_Diagrammer_Graphic_Link_TextItems.htm">TextItems</a> property), but there is no out-of-the box functionality to add other graphic decorations like icons. Here is a&#8230;]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.ilog.fr/products/diagrammernet/documentation/html/ILOGDiagrammerClassLibrary/html/T_ILOG_Diagrammer_Graphic_Link.htm">Link</a> object in ILOG Diagrammer for .NET lets you easily add text items at any position on the link path (using the <a href="http://www.ilog.fr/products/diagrammernet/documentation/html/ILOGDiagrammerClassLibrary/html/P_ILOG_Diagrammer_Graphic_Link_TextItems.htm">TextItems</a> property), but there is no out-of-the box functionality to add other graphic decorations like icons. Here is a <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/08/decoratedlinksample.zip" title="sample">sample</a> that shows how to achieve this.</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/08/decoratedlink.png" title="decoratedlink.png"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/08/decoratedlink.png" alt="decoratedlink.png" /></a></p>
<p>The meat of the sample is the DecoratedLink class. It is a subclass of Link with a new Decorations property that contains a collection of LinkDecoration objects. Each LinkDecoration has an Image property (the icon to display), a Position property (Start, Middle or End) and an Offset property that shifts the icon by the specified number of pixels along the link path.</p>
<p>Here is the source code: <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/08/decoratedlinksample.zip" title="sample">in C#</a>, and <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/08/decoratedlinksample_vb.zip" title="Visual Basic source code">in Visual Basic</a>.</p>
<p>Feel free to use (and adapt) the DecoratedLink class if you need this functionality in your applications.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/08/13/adding-icons-to-a-link/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Diagrammer .NET Tips and Tricks Explained Through the “UML Class Diagram” Sample - Part 3</title>
		<link>http://blogs.ilog.com/netvisu/2008/08/06/diagrammer-net-tips-and-tricks-explained-through-the-%e2%80%9cuml-class-diagram%e2%80%9d-sample-part-3/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/08/06/diagrammer-net-tips-and-tricks-explained-through-the-%e2%80%9cuml-class-diagram%e2%80%9d-sample-part-3/#comments</comments>
		<pubDate>Wed, 06 Aug 2008 15:09:51 +0000</pubDate>
		<dc:creator>Eric Durocher</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Visual Studio]]></category>

		<category><![CDATA[scrollable list]]></category>

		<category><![CDATA[UML class diagram]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/08/06/diagrammer-net-tips-and-tricks-explained-through-the-%e2%80%9cuml-class-diagram%e2%80%9d-sample-part-3/</guid>
		<description><![CDATA[
<h3>Creating a Scrollable List</h3>
In <a href="http://blogs.ilog.com/netvisu/2008/04/25/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample/">part 1</a> and <a href="http://blogs.ilog.com/netvisu/2008/05/19/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample-part-2/">part 2</a> of this series, we explained some common techniques for creating complex ILOG Diagrammer for .NET user symbols, and we used a UMLType symbol as an example.

This post will focus on the description&#8230;]]></description>
			<content:encoded><![CDATA[<h3>Creating a Scrollable List</h3>
<p>In <a href="http://blogs.ilog.com/netvisu/2008/04/25/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample/">part 1</a> and <a href="http://blogs.ilog.com/netvisu/2008/05/19/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample-part-2/">part 2</a> of this series, we explained some common techniques for creating complex ILOG Diagrammer for .NET user symbols, and we used a UMLType symbol as an example.</p>
<p>This post will focus on the description of the List user symbol that is used to display the attributes and operations of the UML type. This List symbol is pretty general, and could be reused in other situations.</p>
<p>You can look at the same <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/04/umlclassdiagram2.zip" title="source code (2)">source code</a> as in the previous post to follow the explanations, since the List symbol was already there.</p>
<p>Here are the graphic elements of the List symbol:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/08/listsymbol.png" title="listsymbol.png"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/08/listsymbol.png" alt="listsymbol.png" /></a></p>
<p>The symbol is made of a DockPanel that contains a StackPanel (which will in turn contain the list items), and three groups of graphic objects that make up a scrollbar (the &#8216;up&#8217; button, the thumb and the &#8216;down&#8217; button). We do not want to use a predefined ILOG Diagrammer for .NET VScrollBar object here because it is a little too big for including it in our UMLType symbol.</p>
<p>Let&#8217;s look at the code to see how the List symbol works. First, we need a property to add items to the list:</p>
<pre>        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public Collection&lt;GraphicObject&gt; Items
        {
            get
            {
                return stacker.Objects;
            }
        }</pre>
<p>The Items property just returns the Objects property of the nested StackPanel, so the items of the list will be added directly to the stacker. Note the DesignerSerializationVisibility attribute that makes sure the items will be serialized even though the collection property itself is read-only.</p>
<p>Now, we want our list to be scrollable (vertically only to keep it simple). For this, we add another property that will define the scroll position:</p>
<pre>        [DefaultValue(0)]
        public int ScrollPosition
        {
            get
            {
                return scrollPosition;
            }
            set
            {
                if (value != scrollPosition)
                {
                    scrollPosition = value;
                    InvalidateLayout();
                }
            }
        }</pre>
<p>The ScrollPosition is an integer, as it specifies a number of items (not a position in pixels): this is simpler since we always want to scroll one whole item at a time.</p>
<p>As you can see, the ScrollPosition does not do much by itself, it just sets an internal member variable to the specified value and calls InvalidateLayout(). The idea is to use the built-in layout mechanism of Diagrammer for .NET to really do the scrolling. The InvalidateLayout() call tells Diagrammer for .NET to call the DoLayout() method of our symbol just before the symbol is next painted on the screen. This makes sure that the scrolling logic will not be executed several times unnecessarily.The DoLayout() method is overridden as follows:</p>
<pre>        protected override void DoLayout()
        {
            dockPanel1.SuspendLayout();
            Rectangle2D bounds = new Rectangle2D(0, 0, Rectangle.Width, dockPanel1.Height);
            stacker.Bounds = bounds;
            stacker.PerformLayout();
            if (Items.Count != 0)
            {
                int pos = scrollPosition;
                if (pos &gt;= Items.Count)
                    pos = Items.Count - 1;
                if (pos &lt; 0)
                    pos = 0;
                bounds.Y = -Items[pos].Y;
                stacker.Bounds = bounds;
            }
            dockPanel1.ResumeLayout(true);
            UpdateArrows();
        }</pre>
<p>What we do here is to move and resize the StackPanel that contains the items according to the ScrollPosition property and to the size of the List symbol. Basically, the top of the stacker is shifted vertically so that the item whose index is ScrollPosition is just at the top of the list. Note the SuspendLayout()/ResumeLayout() calls on the DockPanel that make sure that the parent&#8217;s layout is re-computed only once during this process. Finally, a method called UpdateArrows() is called: it enables or disables the up/down arrows according to the scroll position.</p>
<p>Let&#8217;s talks about the scrollbar now. The idea is simple: the &#8216;up&#8217; bottom will decrease the ScrollPosition by 1, the &#8216;down&#8217; button will increase it, and the thumb will modify the ScrollPosition proportionally to the move.If you look at the code,you will see that it is actually more complex than that:</p>
<ul>
<li> We added timers so that, when you keep the left mouse button pressed in the &#8216;up&#8217; or &#8216;down&#8217; arrows, the list continues to scroll.</li>
<li>We must &#8216;capture&#8217; the mouse to make sure that, when we click in the thumb for instance, the mouse events will continue to move the thumb even if the mouse is not over it any more.</li>
</ul>
<p>Just a final word: as it is, the List symbol is good enough as an element of the UMLType symbol, but it would need a little more polishing before it can be used as a standalone, general list object. In particular, it should behave as a container when it is used in the Visual Studio designer: see <a href="http://blogs.ilog.com/netvisu/2008/07/30/how-to-create-a-user-symbol-that-acts-as-a-container/">this other post</a> that explains how to do this.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/08/06/diagrammer-net-tips-and-tricks-explained-through-the-%e2%80%9cuml-class-diagram%e2%80%9d-sample-part-3/feed/</wfw:commentRss>
		</item>
		<item>
		<title>How to Create a User Symbol That Acts as a Container</title>
		<link>http://blogs.ilog.com/netvisu/2008/07/30/how-to-create-a-user-symbol-that-acts-as-a-container/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/07/30/how-to-create-a-user-symbol-that-acts-as-a-container/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 16:37:31 +0000</pubDate>
		<dc:creator>Eric Durocher</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[container]]></category>

		<category><![CDATA[user symbol]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/07/30/how-to-create-a-user-symbol-that-acts-as-a-container/</guid>
		<description><![CDATA[With ILOG Diagrammer for .NET, you can create user symbols very easily, and this is covered extensively in the user manual and <a href="http://blogs.ilog.com/netvisu/2008/04/25/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample/">this post</a>, among others.

ILOG Diagrammer for .NET also provides several built-in container classes, for example the Canvas&#8230;]]></description>
			<content:encoded><![CDATA[<p>With ILOG Diagrammer for .NET, you can create user symbols very easily, and this is covered extensively in the user manual and <a href="http://blogs.ilog.com/netvisu/2008/04/25/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample/">this post</a>, among others.</p>
<p>ILOG Diagrammer for .NET also provides several built-in container classes, for example the Canvas class, that is very useful to create composite graphic objects.</p>
<p>Something that you may need to do is to combine these two features, that is, create a user symbol that acts as a container. This is pretty easy to do, but there is no sample that shows it, so here we go. We will implement a very simple ContainerSymbol that looks like this:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/containersymbol1.png" title="containersymbol1.png"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/containersymbol1.png" alt="containersymbol1.png" /></a></p>
<p>The ContainerSymbol is a simple rectangular symbol with a title, and it can contain children (two rectangles in the picture above).</p>
<p>As usual, we will use Visual Studio to build our symbol. It is made of a DockPanel that contains a title and a nested Canvas:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/containersymbol2.png" title="containersymbol2.png"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/containersymbol2.png" alt="containersymbol2.png" /></a></p>
<p>Now, we need to add a bit of code to make sure that our symbol will accept children.</p>
<p>First, the symbol must have a property that will hold the collection of children.We will call this property SymbolChildren (not Children, because this is an existing property of the UserSymbol class):</p>
<pre>        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public Collection&lt;GraphicObject&gt; SymbolChildren
        {
            get { return canvas1.Objects; }
        }</pre>
<p>As you can see the SymbolChildren property just returns the Objects property of the nested Canvas, so when a graphic object is added to the SymbolChildren collection, it will really be added to the nested Canvas. Note the DesignerSerializationVisibility attribute: it makes sure the collection&#8217;s contents will be serialized even though the property is read-only.</p>
<p>OK, now we can already add children to our symbol by writing code like this:</p>
<pre>        containerSymbol.SymbolChildren.Add(new Rect(0, 0, 100, 100));</pre>
<p>But we want our symbol to behave like a fully functional container, that is, we want to be able to drag-and-drop children into it when we use the Visual Studio designer. For this, let&#8217;s add this other piece of code:</p>
<pre>        protected override GraphicContainer GetContainerForLogicalChildren()
        {
            return canvas1;
        }</pre>
<p>This override tells the user symbol that it has a special element that will contain the &#8220;logical&#8221; children of the symbol, which means that the children will appear to be added to the symbol, whereas in fact they will be added to the nested Canvas.</p>
<p>Finally, one last piece of code is necessary to make sure that the children of the container symbol are correctly serialized in XML. For this, we need to define a custom designer for our symbol:</p>
<pre>   [Designer(typeof(ParentSymbolDesigner))]
    public partial class ContainerSymbol : UserSymbol
    {</pre>
<pre>        ...</pre>
<pre>    public class ParentSymbolDesigner : UserSymbolDesigner
    {
        protected override PropertyDescriptor GetChildrenPropertyDescriptor()
        {
            return TypeDescriptor.GetProperties(Component)["SymbolChildren"];
        }
    }</pre>
<p>The GetChildrenPropertyDescriptor virtual method tells ILOG Diagrammer for .NET which property to use to serialize the children of the container symbol.</p>
<p>We are done! Our container symbol acts as a basic container, you can add or remove children to it in the Visual Studio designer, select and move the children, etc.<a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/containersymbol.zip" title="containersymbol.zip"></a></p>
<p>Here is the full  <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/containersymbol.zip" title="source code">source code</a> of the sample.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/07/30/how-to-create-a-user-symbol-that-acts-as-a-container/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Adding Smart Tags support to custom User Symbol</title>
		<link>http://blogs.ilog.com/netvisu/2008/07/22/adding-smart-tags-support-to-custom-user-symbol/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/07/22/adding-smart-tags-support-to-custom-user-symbol/#comments</comments>
		<pubDate>Tue, 22 Jul 2008 16:06:39 +0000</pubDate>
		<dc:creator>Patrick Ruzand</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/07/22/adding-smart-tags-support-to-custom-user-symbol/</guid>
		<description><![CDATA[<a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags2.png" title="Smart Tags part 2"></a><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags.png" title="SmartTags in User Symbol"></a><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/winformssmarttag.png" title="winformssmarttag.png"></a><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/gosmarttags.png" title="gosmarttags.png"></a>In the previous "Diagrammer Tips and Tricks" series (see <a target="_blank" href="http://blogs.ilog.com/netvisu/2008/04/25/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample/" title="Tips and tricks part 1">Part 1</a> and <a target="_blank" href="http://blogs.ilog.com/netvisu/2008/05/19/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample-part-2/" title="Tips and Tricks part 2">Part 2</a>), you have learnt how to create a user symbol and how to define design-time capabilities. In this new article, we will explain how to enable Smart Tags&#8230;]]></description>
			<content:encoded><![CDATA[<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags2.png" title="Smart Tags part 2"></a><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags.png" title="SmartTags in User Symbol"></a><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/winformssmarttag.png" title="winformssmarttag.png"></a><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/gosmarttags.png" title="gosmarttags.png"></a>In the previous &#8220;Diagrammer Tips and Tricks&#8221; series (see <a target="_blank" href="http://blogs.ilog.com/netvisu/2008/04/25/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample/" title="Tips and tricks part 1">Part 1</a> and <a target="_blank" href="http://blogs.ilog.com/netvisu/2008/05/19/diagrammer-net-tips-and-tricks-explained-through-the-uml-class-diagram-sample-part-2/" title="Tips and Tricks part 2">Part 2</a>), you have learnt how to create a user symbol and how to define design-time capabilities. In this new article, we will explain how to enable Smart Tags on your custom User Symbol.</p>
<p><strong>Note:</strong> this article requires the ILOG Diagrammer for .NET Patch 14 available on the <a target="_blank" href="https://support.ilog.com/" title="ILOG Support">ILOG Diagrammer for .NET support site</a>.</p>
<h2>What are Smart Tags</h2>
<p>In short, Smart Tags are shortcuts for PropertySheet items accessible from the Visual Studio Design surface and specific to the current selected item. They are natively supported in the Visual Studio WinForms designer through the little arrow icon located at the top-right corner of the current selected object. Clicking on this icon pops up a menu (the Smart Tags panel) populated with items (the Smart Tags items). These items expose a reduced set of design-time configuration entries like properties or verbs (a verb describes a specific action to perform accessible from the PropertySheet). The following image shows the ListBox Smart Tags panel :</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/winformssmarttag.png" title="winformssmarttag.png"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/winformssmarttag.png" alt="winformssmarttag.png" /></a></p>
<p>In Visual Studio, <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags1.png" title="Smart Tags - Step 1"></a>Smart Tags are exposed by means of <a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.designeractionitem.aspx"><strong>DesignerActionItem</strong> </a>instances. A <strong>DesignerActionItem</strong> defines the action to perform when the item is activated. It can be a simple property setter like what the Property Sheet provides, or a more advanced action handled through a method invocation. DesignerActionItem&#8217;s are accessible from the component&#8217;s <a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.componentdesigner.aspx"><strong>ComponentDesigner</strong> </a>through its <a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.designeractionlist.aspx"><strong>DesignerActionList</strong></a>. When a component is selected, the Design environment asks the component designer for its <strong>DesignerActionList</strong> and populates the Smart Tags panel with the DesignerActionItem&#8217;s.</p>
<h2>Smart Tags in ILOG Diagrammer for .NET</h2>
<p>ILOG Diagrammer for .NET extends the Smart Tags support to <strong>GraphicObject</strong> instances, which means that you can define Smart Tags the same way you do in a WinForms custom control. For example, the following pictures shows the Smart Tags items of a <strong>ClosedCurve</strong> :</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/gosmarttags.png" title="gosmarttags.png"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/gosmarttags.png" alt="gosmarttags.png" /></a></p>
<p>To illustrate the article, we will use the <strong>UMLType</strong> user symbol described in the &#8220;Diagrammer Tips and Tricks&#8221; series and the following <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umlclassdiagram.zip" title="Smart Tags Support - VS2008 Project File">VS2008 Project</a>.</p>
<p>As for a WinForms control, adding support for Smart Tags to an ILOG Diagrammer for .NET <strong>UserSymbol</strong> first requires a <strong>ComponentDesigner</strong> associated with the UserSymbol. For <strong>GraphicObject</strong> instances, the ILOG Diagrammer for .NET framework provides the <strong>GraphicObjectDesigner</strong> class that provides a set of services for <strong>GraphicObject</strong> design-time support. It is the base class we inherit from to implement our <strong>UMLType</strong> designer.</p>
<p>We then need to define the action items we want to add to the Smart Tag panel. For the <strong>UMLType</strong> user symbol, the TypeName, Attributes and Operations properties are good candidates. To show the different kind of possible action items, the TypeName property (which is of type <strong>String</strong>) will be exposed in the Smart Tags panel as a standard property in the same way it is exposed in a Property Sheet (that is as a description-textbox pair). The two others (which are specialized Collection) will be exposed as Verbs, which on the UI side are similar to hyperlinks that perform some actions (in our case, it pops up the Collection editor).</p>
<p>In term of implementation, it translates into the following steps :</p>
<ul>
<li>subclass <strong>DesignerActionList</strong></li>
<li>override the <strong><a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.designeractionlist.getsortedactionitems.aspx">GetSortedActionItems()</a></strong> method to populate the list with the action items.</li>
<li>handles the actions corresponding to the action items.</li>
<li>Subclass <strong>GraphicObjectDesigner</strong></li>
<li>override the <strong>CreateActionList</strong> method to return an instance of the <strong>DesignerActionList</strong> subclass.</li>
</ul>
<h2>Implementing the DesignerActionList</h2>
<p>The purpose of a <strong>DesignerActionList</strong> is to provide a list of Smart Tags items to the user symbol designer and to handle the action defined by the items. Populating the list of Smart Tags items is the purpose of the <strong>DesignerActionList.GetSortedActionItems()</strong> method which should be overriden to return the items that apply to the component. Let&#8217;s start with the TypeName property we want to expose since it is the simplest Smart Tags item type.</p>
<p>A property Smart Tags item is defined by the <a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.designeractionpropertyitem.aspx"><strong>DesignerActionPropertyItem</strong> </a>class in the System.ComponentModel.Design namespace. This class easily allows to expose a property in the Smart Tags panel so that it can be edited in-place. The constructor signature is defined as:</p>
<pre>
public DesignerActionPropertyItem(
    string memberName,
    string displayName,
    string category,
    string description)</pre>
<p>The most important parameter is the <em>memberName</em> argument, which refers to the associated property <u>of the <strong>DesignerActionList</strong> subclass</u>. It means that the <strong>UMLType</strong> TypeName property must be duplicated on the <strong>DesignerActionList</strong> as a facade to the underlying <strong>UMLType</strong> component. Here is a first draft of the <strong>UMLTypeActionList</strong> implementation:</p>
<pre>
    class UMLTypeActionList : DesignerActionList {
        public UMLTypeActionList(IComponent component)
            : base(component) {
        }          

        public string TypeName {
            get { return ((UMLType)Component).TypeName; }
            set { UMLTypeDesigner.SetProperty(GetService(typeof(IDesignerHost)) as IDesignerHost,
                                              Component,
                                              value,
                                              "TypeName",
                                              "The name of the UML type.");
            }
        }          

        public override DesignerActionItemCollection GetSortedActionItems() {
            DesignerActionItemCollection items = new DesignerActionItemCollection();
            // The "TypeName" property
            items.Add(new DesignerActionPropertyItem("TypeName",
                                                     "Type name",
                                                     "UML",
                                                     "The name of the UML type."));
            return items;
        }
    }</pre>
<p>In the code above, the TypeName property setter invokes the <strong>UMLTypeDesigner.SetProperty</strong> method, which is a convenient method allowing to perform an undoable property setting.</p>
<p>In order to be able to test our action list implementation, we need to implement the <strong>UMLType</strong> designer and associate it with the UMLType component so that the Design-time API supports it. As mentioned above, the <strong>UMLType</strong> designer inherits from the <strong>GraphicObjectDesigner</strong> class and in this simple use case, the only method we need to override is the <strong>CreateActionList()</strong> factory method that returns an instance of the <strong>UMLTypeActionList</strong> class. Here is the implementation:</p>
<pre>
    public class UMLTypeDesigner : GraphicObjectDesigner {
        protected override System.ComponentModel.Design.DesignerActionList CreateActionList() {
            return new UMLTypeActionList(this.Component);
        }
    }</pre>
<p>Finally, the last step is to associate this designer class to the <strong>UMLType</strong> class by means of the <a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.designerattribute.aspx"><strong>DesignerAttribute</strong> </a>class attribute:</p>
<pre>
    [Designer(typeof(UMLTypeDesigner), typeof(IDesigner))]
    public partial class UMLType : UserSymbol
    {
      ...
    }</pre>
<p>Running the sample at this stage gives the following result (after having added our assembly to the Visual Studio Toolbox while in diagram editing mode) :</p>
<p> <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags1.png" title="Smart Tags - Step 1"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags1.png" alt="Smart Tags - Step 1" /></a></p>
<p>Ok. But what about use cases where you need more than just editing a property value ? For example, you may need to define complex actions like defining a data binding-like wizard-driven process that can be started from the Smart Tags panel. To address these use cases, the design-time API provides the <strong>DesignerActionMethodItem</strong> class which instead of relying on a property invokes a specified method that will handle the action. This is what we are going to use for the Operations and Attributes UMLType members. Instead of being exposed as a Property action item, they will be displayed as an &#8220;HyperLink&#8221;. When clicked, a modal dialog displaying the associated <strong>UITypeEditor</strong> (here the standard collection editor) will be shown.</p>
<h2>Invoking the UITypeEditor from a Smart Tags item.</h2>
<p>In the WinForms design-time API documentation, a <a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.drawing.design.uitypeeditor.aspx"><strong>UITypeEditor</strong> </a>is defined as an editor &#8220;that can provide a user interface for representing and editing the values of objects of the supported data types&#8221;. In the sample we are writing, we will use the <strong>UITypeEditor</strong> associated with the Operations and Attributes properties and invoke its <strong>EditValue()</strong> method to edit the object&#8217;s value. Typical <strong>UITypeEditor</strong> implementations are meant to work with a PropertyGrid component, and as such are (in most cases) expecting an <strong><a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.windows.forms.design.iwindowsformseditorservice.aspx">IWindowsFormsEditorService</a></strong>, as explains the Microsoft documentation (&#8221;This service is typically used to display a form from the EditValue method of a UITypeEditor&#8221;). Since a <strong>IWindowsFormsEditorService</strong> instance is available only from the PropertyGrid control, we have to write our own implementation. Let&#8217;s name it <strong>EditorService</strong>, and for convenient reasons, it will also implements the <strong>ITypeDescriptorContext</strong> and the ServiceProvider interfaces since the <strong>UITypeEditor.EditValue</strong> method expects such services.</p>
<p>As previously mentioned, the corresponding Attributes or Operations <strong>DesignerActionMethodItem</strong>&#8217;s should display a modal dialog holding the associated <strong>UITypeEditor</strong> (the CollectionEditor in this case). For this purpose, our <strong>IWindowsFormsEditorService</strong> implementation (the <strong>EditorService</strong> class) must implement the <strong>ShowDialog(Form dialog)</strong> method to basically invoke the <strong>Form.ShowDialog</strong> method on the <em>dialog</em> parameter. This method allows to specify the dialog owner via the owner&#8217;s Win32 HWND. In our case, the dialog owner to specify is simply the Smart Tags window that is exposed in the ILOG Diagrammer for .NET library by means of the <strong>ILOG.Diagrammer.Design.IDropDownOwner</strong> interface (introduced in patch 14). This interface is implemented by the DesignerHost RootComponent&#8217;s designer and represents a possible candidate for dialog ownership.</p>
<p>While it may appear quite complex, the following piece of code will clear up everything:</p>
<pre>
        DialogResult IWindowsFormsEditorService.ShowDialog(Form dialog) {
            IDesignerHost host =
              (IDesignerHost)((IServiceProvider)this).GetService(typeof(IDesignerHost));
            IDropDownOwner rootDesigner = null;
            if (host != null)
                rootDesigner = host.GetDesigner(host.RootComponent) as IDropDownOwner;
            if (rootDesigner == null) {
                IUIService srv =
                  (IUIService)((IServiceProvider)this).GetService(typeof(IUIService));
                if (srv != null)
                    return srv.ShowDialog(dialog);
            }
            if (rootDesigner != null) {
                IWin32Window owner = rootDesigner.DropDownOwner;
                if (owner != null)
                    return dialog.ShowDialog(owner);
            }
            return dialog.ShowDialog(_component as IWin32Window);
        }</pre>
<p>The implementation first retrieves the <strong><a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.idesignerhost.aspx">IDesignerHost</a></strong>, then tries to get the RootComponent&#8217;s designer as a <strong>IDropDownOwner</strong>. Then, if successful, it invokes dialog.ShowDialog() method passing the Smart Tags window HWND as the dialog owner (the return value of rootDesigner.DropDownOwner).</p>
<p>So, with this EditorService class, we now have everything we need to write the Attributes and Operations <strong>DesignerActionMethodItem</strong> instances.</p>
<p>The DesignerActionMethodItem constructor is defined as:</p>
<pre>
public DesignerActionMethodItem(
    DesignerActionList actionList,
    string memberName,
    string displayName,
    string category,
    string description,
    bool includeAsDesignerVerb
)</pre>
<p>where <em>memberName</em> specifies the method to invoke <u>on the DesignerActionList instance</u>.</p>
<p>The following code shows the implementation corresponding to the Attributes property (you can refer to the full source code for the Operations property and the complete <strong>EditorService</strong> implementation).</p>
<pre>
    class UMLTypeActionList : DesignerActionList {
        ...
        public void EditAttributes() {
            EditorService.EditValue(Component.Site, Component, "Attributes");
        }
        public override DesignerActionItemCollection GetSortedActionItems() {
            DesignerActionItemCollection items =
                new DesignerActionItemCollection();
            // The "TypeName" property
            ...
            // The 'Edit Attributes...' verb
            items.Add(new DesignerActionMethodItem(this,
                                    "EditAttributes",
                                    "Edit Attributes...",
                                    "UML",
                                    "The attributes of the UML type.",
                                    true));
        }
    }</pre>
<p>And here is the final result:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags2.png" title="Smart Tags part 2"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/07/umltypesmarttags2.png" alt="Smart Tags part 2" /></a></p>
<p>In this article, we have seen how to support Smart Tags from a custom ILOG Diagrammer for .NET User Symbol. Using the same design-time API as the Windows Forms controls, it integrates seamlessly with the Visual Studio design surface and greatly improves the user experience of your symbols.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/07/22/adding-smart-tags-support-to-custom-user-symbol/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Creating Default Anchors for custom User Symbols</title>
		<link>http://blogs.ilog.com/netvisu/2008/06/26/creating-default-anchors-for-custom-user-symbols/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/06/26/creating-default-anchors-for-custom-user-symbols/#comments</comments>
		<pubDate>Thu, 26 Jun 2008 12:22:25 +0000</pubDate>
		<dc:creator>Robert Dupuy</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[connect]]></category>

		<category><![CDATA[default anchors]]></category>

		<category><![CDATA[link]]></category>

		<category><![CDATA[user symbol]]></category>

		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/06/26/creating-default-anchors-for-custom-user-symbols/</guid>
		<description><![CDATA[This article describes how to create default anchors on custom user symbols with <a href="http://www.ilog.com/products/diagrammernet/">ILOG Diagrammer for .NET</a>.

First, we need to make sure that we know what anchors and user symbols are. Let's briefly define these two notions:
<ul>
	<li>A <strong>user&#8230;</strong></li></ul>]]></description>
			<content:encoded><![CDATA[<p>This article describes how to create default anchors on custom user symbols with <a href="http://www.ilog.com/products/diagrammernet/">ILOG Diagrammer for .NET</a>.</p>
<p>First, we need to make sure that we know what anchors and user symbols are. Let&#8217;s briefly define these two notions:</p>
<ul>
<li>A <strong>user symbol</strong> is a graphic object built with the<strong> </strong><span id="nsrTitle"><strong>ILOG Diagrammer for .NET Diagram Designer</strong>. This designer, fully integrated into Visual Studio, is a WYSIWYG editor that produces C# or VB.NET code. Using this editor, you can build complex interactive symbols by assembling available shapes and symbols.</span></li>
<li>An anchor is a point on a graphic object where a link can be connected. Each graphic object has a collection of anchors on which it&#8217;s possible to connect links.</li>
</ul>
<p>Now that we know what we&#8217;re talking about, we can imagine the following scenario: A user has created a custom user symbol using our designer, and he wants to specify the exact location where links could be connected to this symbol. For example, when designing an electrical symbol, one need to specify that wires can be connected to the component terminals. Here is an example of such a symbol:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/transistor.png" title="Transistor"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/transistor.png" alt="Transistor" /></a></p>
<p>Let&#8217;s create this symbol in Visual Studio:</p>
<ol>
<li>Launch Visual Studio 2005 or 2008.</li>
<li>Select <strong>File</strong>-&gt;<strong>New</strong>-&gt;<strong>Project</strong>-&gt;<strong>ILOG Diagrammer Symbol Library</strong> and name the project <strong>ElectricalSymbolsLibrary</strong>.</li>
<li>In the solution explorer, right click on the project, and choose <strong>Add New Item</strong>-&gt;<strong>UserSymbol (ILOG Diagrammer) </strong>and name the symbol <strong>Transistor.cs.</strong></li>
<li>Choose <strong>Diagrammer</strong>-&gt;<strong>Import File</strong> and import <strong>transistor.ivn</strong> after extracting it from the following <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/transistor.zip">archive</a>. Click <strong>Yes</strong> in the dialog asking if you want to import the file as vector graphics.</li>
</ol>
<p>You should now have your transistor symbol visible in the designer:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical.png" title="ILOG Diagrammer for .NET Diagram Designer"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical.png" alt="ILOG Diagrammer for .NET Diagram Designer" /></a></p>
<p>Let&#8217;s now use this new symbol in a diagram so that we can try to connect links to it. To add a diagram to the project, right-click in the solution explorer on the project and choose <strong>Add</strong>-&gt;<strong>New Item</strong>-&gt;<strong>Diagram (ILOG Diagrammer). </strong>Compile the project (<strong>Build</strong>-&gt;<strong>Build Solution</strong>) to update the toolbox. Open the toolbox, your new transistor symbol should be available:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical2.png" title="ILOG Diagrammer for .NET Diagram Designer"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical2.png" alt="ILOG Diagrammer for .NET Diagram Designer" /></a></p>
<p>Drag a transistor symbol from the toolbox to the design surface. Repeat the operation to have several symbols in the diagram. You should now have something like this:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical3.png" title="ILOG Diagrammer for .NET Diagram Designer"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical3.png" alt="ILOG Diagrammer for .NET Diagram Designer" /></a></p>
<p>Let&#8217;s now try to connect the transistors together by creating links between them. Open the toolbox and locate the <strong>Connectors</strong> tab. Click on one of the links available in the tab, then move the mouse over one of the transistors. The anchors where the link can be connected are highlighted:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical4.png" title="Anchors highlighted"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical4.png" alt="Anchors highlighted" /></a></p>
<p>We can see that by default a user symbol has four anchors, each one located at the middle of the bounding box sides. Obviously, that&#8217;s not what we want here. One way to get the right anchors is to edit each transistor instance by modifying its anchors collection: After removing the default anchors (set the <strong>UseDefaultAnchors</strong> property to <strong>false</strong>), add three <strong>BoundsAnchor</strong> to the anchors collection (right-click on the transistor, and choose <strong>Edit Anchors&#8230;</strong>). Then, we need to move each anchor at the desired location. To do this, choose the <strong>Edit Anchors</strong> (<a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical5.png" title="Edit Anchors"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical5.png" alt="Edit Anchors" /></a>) icon from the Diagrammer toolbar and move the mouse over the transistor. It&#8217;s now possible to move the three anchors previously added to their right location by clicking each anchor and dragging it to its desired location. Then, if we go back to the link mode connection by clicking on a link in the toolbox <strong>Connectors</strong> tab, we can see by passing the mouse over it, that our transitor has now its anchors placed at their right location:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical6.png" title="Electrical"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical6.png" alt="Electrical" /></a></p>
<p>The main drawbacks of this approach are:</p>
<ul>
<li>The anchors are not part of the symbol itself, since they have been added after the symbol creation. If you create an instance of this symbol by code, your new anchors will not be available.</li>
<li>We&#8217;re not using the default anchors feature of the graphic objects, and thus, anchors are created and added to the component model even though there are no links connected to them. This can be a performance issue if you have many objects with many anchors.</li>
</ul>
<p>An alternative to this approach is to define the default anchors directly when designing the transistor. How can we do this ? Let&#8217;s go back to the designer view of our transistor by double clicking the <strong>Transistor.cs</strong> file in the <strong>Solution Explorer</strong>. The trick is that all the real anchors (not the default ones) defined in the sub objects of our transistor will be exposed as default anchors for our user symbol. Thus, we simply need to add three anchors on the sub objects composing our transistor. Let&#8217;s see how to do it.</p>
<p>If you look at the <strong>Document Outline</strong> view in Visual Studio, you will see that our transistor is composed of several shapes:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical7.png" title="Electrical7"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical7.png" alt="Electrical7" /></a></p>
<p>The interesting objects are the <strong>polyline1</strong>, <strong>polyline2</strong> and <strong>line1</strong> objects. On each one, we will add a new <strong>PolyPointsAnchor</strong>, which is a type of anchor whose location is bound to a vertex of a polyline object. Right-click on the <strong>polyline1</strong> object in the designer view, and choose  <strong>Edit Anchors</strong>. Add a <strong>PolyPointsAnchor </strong>and click the <strong>OK</strong> button. Repeat the operation for the <strong>polyline2</strong> and <strong>line1</strong> objects. Note that in our example, the anchors are located on the first vertex of each polyline, which is the default for <strong>PolyPointsAnchor</strong> objects<strong>.</strong></p>
<p>Let&#8217;s compile the project and switch back to our diagram view to test our transistor by double clicking the <strong>Diagram1.cs</strong> file in the <strong>Solution Explorer</strong>. To start with a fresh diagram, remove existing instances of the transistors. Then drag and drop a new transistor from the toolbox and try to connect a link to see that the highlighted anchors are the expected ones:</p>
<p><a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical8.png" title="Electrical8"><img src="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/electrical8.png" alt="Electrical8" /></a></p>
<p>We&#8217;ve successfully changed the default anchors of our transistor, without having to write a single line of code.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/06/26/creating-default-anchors-for-custom-user-symbols/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Creating Bezier Curves in an  Ajax DiagramView (Part 2)</title>
		<link>http://blogs.ilog.com/netvisu/2008/06/20/create-bezier-curve-in-an-ajaxdiagramview-part-2/</link>
		<comments>http://blogs.ilog.com/netvisu/2008/06/20/create-bezier-curve-in-an-ajaxdiagramview-part-2/#comments</comments>
		<pubDate>Fri, 20 Jun 2008 09:32:20 +0000</pubDate>
		<dc:creator>Patrick Ruzand</dc:creator>
		
		<category><![CDATA[.NET]]></category>

		<category><![CDATA[Ajax]]></category>

		<category><![CDATA[Diagram]]></category>

		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blogs.ilog.com/netvisu/2008/06/20/create-bezier-curve-in-an-ajaxdiagramview-part-2/</guid>
		<description><![CDATA[<a href="http://blogs.ilog.com/netvisu/2008/06/10/creating-bezier-curves-in-an-ajax-diagramview-part-1/" title="Part 1">In the previous article</a>, I have explained the fundations of the Ajax interaction framework of <a target="_blank" href="http://www.ilog.com/products/diagrammernet/" title="ILOG Diagrammer for .NET">ILOG Diagrammer for .NET</a>. It is now time to dive into the implementation details.

From the first article, we know an <code>AjaxDiagramView</code> interactor inherits from the&#8230;]]></description>
			<content:encoded><![CDATA[<p><a href="http://blogs.ilog.com/netvisu/2008/06/10/creating-bezier-curves-in-an-ajax-diagramview-part-1/" title="Part 1">In the previous article</a>, I have explained the fundations of the Ajax interaction framework of <a target="_blank" href="http://www.ilog.com/products/diagrammernet/" title="ILOG Diagrammer for .NET">ILOG Diagrammer for .NET</a>. It is now time to dive into the implementation details.</p>
<p>From the first article, we know an <code>AjaxDiagramView</code> interactor inherits from the <code>System.Web.UI.ExtenderControl</code> class. As such, it is composed of two parts: an ASP.NET server control and a JavaScript client control.</p>
<h2>The server control</h2>
<p>The ASP.NET server control is responsible for describing the client resources to the underlying ASP.NET framework (the script resources to deploy, the optional initialization tasks to perform on the client, etc.), and for handling the possible actions coming from the client control. In our case, the server control implementation handles the client action (i.e. create an <code>ILOG.Diagrammer.Graphic.BezierCurve</code> instance and add it to the view content) via an asynchronous callback. Let&#8217;s first begin with the implementation of the client resources description.</p>
<p>For this purpose, the <code>ILOG.Diagrammer.Web.UI.ViewInteractor</code> class defines the following methods:</p>
<pre>
ScriptBehaviorDescriptor CreateScriptBehaviorDescriptor(Control targetControl)
IEnumerable&lt;ScriptReference&gt; GetScriptReferences()</pre>
<p>The <code>CreateScriptBehaviorDescriptor</code> method must be overriden to return a <code>ScriptBehaviorDescriptor</code> instance that specifies the name of the client-side class of the interactor (in other words the name of the JavaScript class).<br />
The <code>GetScriptReferences</code> method returns the script resources needed by your client control. This is needed by ASP.NET to be able to automatically deploy the required client resources.</p>
<p>Here is a first implementation of the <code>MakeBezierCurveInteractor</code> class that illustrates the implementation of these methods :</p>
<pre>
public class MakeCurveInteractor : ViewInteractor {        

  protected override ScriptBehaviorDescriptor CreateScriptBehaviorDescriptor(Control targetControl) {
    return new ScriptBehaviorDescriptor("AjaxBezierSample.MakeCurveBehavior",
                                        targetControl.ClientID);
  }                

  protected override IEnumerable&lt;scriptreference&gt; GetScriptReferences() {
    IEnumerable&lt;ScriptReference&gt; references = base.GetScriptReferences();
    List&lt;ScriptReference&gt; list = new List&lt;ScriptReference&gt;(references);
    list.Add(new ScriptReference("AjaxBezierSample.script.MakeCurveBehavior.js",
                                 Assembly.GetExecutingAssembly().FullName));
    return list;
  }</pre>
<p>which means the client control implementation is the <code>AjaxBezierSample.MakeCurveBehavior</code> class defined in the MakeCurveBehavior.js file, packaged as an embedded resource in the application assembly (packaging a script resource in the assembly requires the .js file be built with the Embedded Resource build action, and the resource declared in the AssemblyInfo.cs).</p>
<p>The next step, and it completes the server control implementation, is to handle the action. As explained above, we made the choice to process the interaction via an asynchronous ASP.NET callback, which is possible because the <code>ViewInteractor</code> base class implements the ASP.NET 2.0 <code>ICallbackEventHandler</code> interface. Therefore, our custom interactor must override the <code>ViewInteractor.RaiseCallBackEvent</code> method that is called when a callback request is received by our control.</p>
<p>The implementation is quite straightforward: it first reads the curve definition points from the method parameter (passed by the client control as a JSON string), converts these points from the view coordinate system to the view graphic container coordinate system, then creates the corresponding Diagrammer for .NET graphic object (a <code>BezierCurve</code> instance) and finally adds it to the view graphic container.</p>
<p>Here is the code:</p>
<pre>
        protected override void RaiseCallbackEvent(string eventArgument) {
            ProcessRequest(eventArgument);
            base.RaiseCallbackEvent(eventArgument);
        }
        protected virtual void ProcessRequest(string eventArgument) {
            if (string.IsNullOrEmpty(eventArgument))
                return;
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(BezierArg));
            BezierArg args = null;
            using (Stream input = new MemoryStream(Encoding.Unicode.GetBytes(eventArgument))) {
                args = serializer.ReadObject(input) as BezierArg;
            }
            if (args != null) {
                Point2D[] points = args.points;
                if (points.Length == 0)
                    return;
                Transform t = View.Transform.Inverse();
                t.TransformPoints(points);
                BezierCurve curve = new BezierCurve(points);
                IManageChildren container = View.Content as IManageChildren;
                if (container != null) {
                    container.AddChildren(new GraphicObject[] { curve });
                }
            }
        }</pre>
<p>The server control implementation is done. It&#8217;s now time to wear our JavaScript developer suit for the client side control implementation. From now on, all class names refer to the Microsoft JavaScript Library.</p>
<h2>The client control</h2>
<p>Implementing the client part of a <code>ViewInteractor</code> consists on writing a JavaScript class inheriting from the <code>ILOG.Diagrammer.Web.UI.ViewBehavior</code> class which offers the basic services to communicate with the server control. In the Microsoft JavaScript world, writing a new class consists on :</p>
<ul>
<li>defining the namespace</li>
<li>defining the class object</li>
<li>implementing the class methods via the class object prototype</li>
<li>registering the class in the class hierarchy</li>
</ul>
<p>In terms of code, it means:</p>
<ul>
<li>defining the name space:</li>
</ul>
<pre><font size="2">Type.registerNamespace(</font><font size="2" color="#a31515">&#8216;AjaxBezierSample&#8217;</font><font size="2">);</font></pre>
<p>This line of code creates a new namespace called &#8216;AjaxBezierSample&#8217; and registers it in the <code>Type</code> object.</p>
<ul>
<li>defining the class object:</li>
</ul>
<pre>AjaxBezierSample.MakeCurveBehavior = <font color="#0000ff">function</font>(element) {
  &#8230;
  AjaxBezierSample.MakeCurveBehavior.initializeBase(<font color="#0000ff">this</font>, [element]);
};</pre>
<p>The namespace object being created, we define the MakeCurveBehavior class object (the constructor) and call the initializeBase() method to initialize the base class. Latter, we will add to the constructor the fields initialization code.</p>
<ul>
<li>implementing the class methods via the class object prototype</li>
</ul>
<pre>
AjaxBezierSample.MakeCurveBehavior.prototype = {
  initialize : <font color="#0000ff">function</font>() {
    AjaxBezierSample.MakeCurveBehavior.callBaseMethod(<font color="#0000ff">this</font>, <font color="#a31515">&#8216;initialize&#8217;</font>);
  },
  dispose : <font color="#0000ff">function</font>() {
    AjaxBezierSample.MakeCurveBehavior.callBaseMethod(<font color="#0000ff">this</font>, <font color="#a31515">&#8216;dispose&#8217;</font>);
  },
  &#8230;
}</pre>
<p>The methods of the class are defined on the prototype following the prototype model. For more information on the prototype model, see the <a target="_blank" href="http://asp.net/AJAX/Documentation/Live/tutorials/CreatingClientComponentPrototype.aspx"></a>title=&#8221;Prototype model&#8221;&gt;MSDN documentation. For the time being, we only need to call the <code>initialize()</code> and <code>dispose()</code> methods of the base class.</p>
<ul>
<li>registering the class in the class hierarchy</li>
</ul>
<pre>
AjaxBezierSample.MakeCurveBehavior.registerClass(<font color="#a31515">&#8216;AjaxBezierSample.MakeCurveBehavior&#8217;</font>, ILOG.Diagrammer.Web.UI.ViewBehavior);</pre>
<p>Finally, we register our new class in the class hierarchy, specifying its fully qualified name (that is the class name prefixed with the namespace) and the base class it inherits from. This skeleton is the minimum code required to fully define a new <code>ViewBehavior</code> subclass.</p>
<p>The last step is to eventually implement the code needed to create bezier curves.</p>
<h2>Drawing Bezier curves in DHTML</h2>
<p>As explained in the first part of this article, the interaction ghost of the bezier curves will be implemented either in VML or SVG depending on the browser. The ghost will be composed of three primitive objects:</p>
<ul>
<li>a circle that represents the edited passage point.</li>
<li>two rectangles that represent the control points.</li>
</ul>
<p>These primitives will be added to a parent container positionned in absolute above the image. To ease the primitives update, both the primitives and the container will have a corresponding class field (a reference to the corresponding node in the DOM).</p>
<p>The code below shows the updated constructor (with the primitive fields) and the DOM initialization :</p>
<pre>
AjaxBezierSample.MakeCurveBehavior = function(element) {
    this._ghostContainer = null;
    this._ptMarker = null;
    this._ctrl1 = null;
    this._ctrl2 = null;
    this._useVML = Sys.Browser.agent == Sys.Browser.InternetExplorer;
    this._curveCount = 0;
    this._svg  = null;
    ...
    AjaxBezierSample.MakeCurveBehavior.initializeBase(this, [element]);
};        

AjaxBezierSample.MakeCurveBehavior.prototype = {        

    initialize : function() {
        AjaxBezierSample.MakeCurveBehavior.callBaseMethod(this, 'initialize');
        ...
        this.initDOM();
    },
    initDOM : function() {
        this._ghostContainer = document.createElement("div");
        this.get_element().appendChild(this._ghostContainer);
        this._ghostContainer.style.zIndex = 3;
        this._ghostContainer.style.position = "absolute";
        this._ghostContainer.style.left="0px";
        this._ghostContainer.style.top="0px";
        this._ghostContainer.style.width="100%";
        this._ghostContainer.style.height="100%";
        if (!this._useVML) {
            this._svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            this._ghostContainer.appendChild(this._svg);
        }
        var parentNode = this._useVML ? this._ghostContainer : this._svg;
        // passage point marker
        this._ptMarker = this.createMarker(parentNode);
        // control points markers
        this._ctrl1 = this.createControlPt(parentNode, 'ctrl1');
        this._ctrl2 = this.createControlPt(parentNode, 'ctrl2');
    },        

    createMarker : function(parentNode) {
        var marker = this._useVML ? this._createMarkerVML(parentNode) : this._createMarkerSVG(parentNode);
        return marker;
    },        

    _createMarkerVML : function(parentNode) {
        var marker = document.createElement("oval");
        parentNode.appendChild(marker);
        marker.id = "ptmarker";
        marker.style.behavior = "url(#default#VML)";
        marker.strokeweight = 1;
        marker.filled = 'true';
        marker.fillcolor = 'black';
        marker.style.position = "absolute";
        marker.style.width = "7px";
        marker.style.height = "7px";
        marker.style.display='none';
        return marker;
    },        

    _createMarkerSVG : function(parentNode) {
        var marker = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        parentNode.appendChild(marker);
        marker.style.display = 'none';
        marker.setAttributeNS(null, 'id', "ptmarker");
        marker.setAttributeNS(null, 'r', 3);
        marker.setAttributeNS(null, "fill", 'black');
        marker.setAttributeNS(null, "stroke", "none");
        return marker;
    },        

    createControlPt : function(parentNode, id) {
        var ctrl = this._useVML ? this._createControlVML(parentNode, id) : this._createControlSVG(parentNode, id);
        return ctrl;
    },        

    _createControlVML : function(parentNode, id) {
        var ctrl = document.createElement("rect");
        parentNode.appendChild(ctrl);
        ctrl.id = id;
        ctrl.style.behavior = "url(#default#VML)";
        ctrl.strokeweight = 1;
        ctrl.filled = 'false';
        ctrl.style.position = 'absolute';
        ctrl.style.width = '11px';
        ctrl.style.height = '11px';
        ctrl.style.display='none';
        return ctrl;
    },        

    _createControlSVG : function(parentNode, id) {
        var ctrl = document.createElementNS("http://www.w3.org/2000/svg", "rect");
        parentNode.appendChild(ctrl);
        ctrl.id = id;
        ctrl.setAttributeNS(null, "width", "11px");
        ctrl.setAttributeNS(null, "height", "11px");
        ctrl.setAttributeNS(null, "stroke-width", 1);
        ctrl.setAttributeNS(null, "fill", "none");
        ctrl.setAttributeNS(null, "stroke", "black");
        ctrl.style.display='none';
        return ctrl;
    },</pre>
<h2>Handling interactions</h2>
<p>The interaction process follows the following sequences:</p>
<ul>
<li>When the left mouse button is pressed, a new passage point and two control points are created.</li>
<li>When the mouse is dragged, the position of the control points is adjusted accordingly.</li>
<li>On a double-click, the curve is validated and a request is sent to the server with the curve points.</li>
<li>When the ESC key is pressed, the interaction is cancelled.</li>
</ul>
<p>Therefore, the interactor has to listen the mousedown, mousemove, mouseup and keydown events. For this purpose, we define four handlers that will be wired/unwired depending on the value of the <code>active</code> property.</p>
<p>The code below shows the handler initialization and the required methods to wire/unwire the handlers on a <code>active</code> property change:</p>
<pre>
AjaxBezierSample.MakeCurveBehavior = function(element) {        

    this._mouseDownHandler = null;
    this._mouseMoveHandler = null;
    this._mouseUpHandler = null;
    this._keyDownHandler = null;
    this._propertyChangedHandler = null;
    this._startPoint = null;
    this._points = null;
    this._size = 0;
    ...        

    AjaxBezierSample.MakeCurveBehavior.initializeBase(this, [element]);
};
AjaxBezierSample.MakeCurveBehavior.prototype = {        

    initialize : function() {
        /// <summary></summary>
        /// Initializes a MakeCurveBehavior instance.
        ///         

        AjaxBezierSample.MakeCurveBehavior.callBaseMethod(this, &#8216;initialize&#8217;);        

        this._mouseDownHandler = Function.createDelegate(this, this._onMouseDown);
        this._mouseMoveHandler = Function.createDelegate(this, this._onMouseMove);
        this._mouseUpHandler = Function.createDelegate(this, this._onMouseUp);
        this._keyDownHandler = Function.createDelegate(this, this._onKeyDown);
        this._doubleClickHandler = Function.createDelegate(this, this._onDoubleClick);
        if (this.get_active()) {
            this._wireHandlers();
        }
        this._propertyChangedHandler = Function.createDelegate(this, this._onPropertyChanged);
        this.add_propertyChanged(this._propertyChangedHandler);
        &#8230;
    },        

    dispose : function() {
        this._imgElt = null;
        $clearHandlers(this.get_element());
        AjaxBezierSample.MakeCurveBehavior.callBaseMethod(this, &#8216;dispose&#8217;);
    },        

    _wireHandlers : function() {
        $addHandler(this.get_element(), &#8216;mousedown&#8217;, this._mouseDownHandler);
        $addHandler(this.get_element(), &#8216;mousemove&#8217;, this._mouseMoveHandler);
        $addHandler(this.get_element(), &#8216;mouseup&#8217;, this._mouseUpHandler);
        $addHandler(this.get_element(), &#8216;keydown&#8217;, this._keyDownHandler);
        $addHandler(this.get_element(), &#8216;dblclick&#8217;, this._doubleClickHandler);
        this.ensureFirefoxKeyEvents();
    },        

    _unwireHandlers : function() {
        $removeHandler(this.get_element(), &#8216;mousedown&#8217;, this._mouseDownHandler);
        $removeHandler(this.get_element(), &#8216;mousemove&#8217;, this._mouseMoveHandler);
        $removeHandler(this.get_element(), &#8216;mouseup&#8217;, this._mouseUpHandler);
        $removeHandler(this.get_element(), &#8216;keydown&#8217;, this._keyDownHandler);
        $removeHandler(this.get_element(), &#8216;dblclick&#8217;, this._doubleClickHandler);
    },        

    _onPropertyChanged : function(sender, args) {
        if (&#8217;active&#8217; == args.get_propertyName()) {
            if (this.get_active()) {
                this._wireHandlers();
            } else {
                this._unwireHandlers();
            }
        }
    },</pre>
<p>Next, we need to handle the points and create the ghost curve. For this purpose, all the points (the passage points and the control points) are stored in an array in the following sequence : the passage point, the first control point, the second control point. We hence have three indices per point.</p>
<p>The code below illustrates this (for the sake of readability, the method updateCurveGhostPoints() that updates the ghost position is not shown. Please refer to the source code for more details). When the mouse is pressed, the addPoint() method is invoked to add a new passage point and two control points. The three points have initially the same coordinates until the next mouse drag. Then, when the mouse is dragged, the control points position is adjusted proportionally (in the react() method) :</p>
<pre>
    _onMouseDown : function(e) {
        if (e.button == Sys.UI.MouseButton.leftButton) {        

            if (this._points == null) {
                this._points = [];
                this._size = 0;
            }
            this._dragging = true;
            var loc = Sys.UI.DomElement.getLocation(this.get_element());
            var p = {'x':e.clientX - loc.x, 'y':e.clientY - loc.y };
            // Add the new point
            this._addPoint(p);
            // ... and compute the control points
            this._react(p);
            // update ghost
            if (this._size == 0) {
                this.updateCurveGhostPoints();
            } else {
                this._points[this._size-1] = p;
                this.addNewCurve();
            }
            this.updateMarkerPos(p);
            this.onStartInteraction();        

            e.stopPropagation();
            e.preventDefault();
        }
    },        

    _onMouseMove : function(e) {
        if (this._size &gt; 0 &amp;&amp; this._dragging) {
            var loc = Sys.UI.DomElement.getLocation(this.get_element());
            var p = {'x':e.clientX - loc.x, 'y':e.clientY - loc.y };
            if (this._size == 1) {
                // If user is dragging the starting point, add the second point.
                this._addPoint(p);
                // and compute the control points
                this._react(p);
            } else {
                // computes the control points position
                this._react(p);
                this._points[this._size-1] = p;
            }
            // update ghost
            this.updateCurveGhostPoints();        

            e.stopPropagation();
            e.preventDefault();
        }
    },        

    _addPoint : function(p) {
        if (this._size &gt; 1) {
            this._points[(++this._size)-1] = p;
            this._points[(++this._size)-1] = p;
            this._points[(++this._size)-1] = p;
        } else {
            this._points[(++this._size)-1] = p; // start point
        }
    },        

    _react : function(p) {
        if (this._size &gt; 3) {
           // Updates the position of the control point.
           var prevp = this._size - 3; // previous left handle
           var pivot = this._size - 2; // previous end point
           this._points[prevp] = this.symmetric(this._points[pivot], p);
        }
    },        

    _onMouseUp : function(e) {
        this._dragging = false;        

    },        

    _onDoubleClick : function(e) {
        if (this._points != null) {
            // Commit the action.
            this.doCreateCurve();
            this.onEndInteraction();
            this.reset();        

            e.stopPropagation();
            e.preventDefault();
        }
    },        

    _onKeyDown : function(e) {
        if (this._points != null &amp;&amp; e.keyCode == Sys.UI.Key.esc) {
            // Cancel interaction
            this.onEndInteraction();
            this.reset();
            e.stopPropagation();
            e.preventDefault();
        }
    },</pre>
<h2>Commit the new curve to the server</h2>
<p>Finally, the points defining the new curve are sent to the server-side part of our interactor to create the corresponding <code>ILOG.Diagrammer.Graphic.BezierCurve</code> object and add it to the view <code>GraphicContainer</code>. To do this, we create an asynchronous ASP.NET callback invoking the <code>ViewBehavior.callServerAsync</code> method passing the points array as parameter. At this time, the request has been processed but the image has not been updated to show the new content. In order to fix this, we override the ViewBehavior.onCallbackReceived method to refresh the view when the callback response is received :</p>
<pre>
    doCreateCurve : function() {
        var args = {};
        if (this._size &gt; 4) {
            // get rid of the extra passage point coming from the double-click.
            if (this._useVML)
                args.points = this._points.slice(0, this._points.length-1-3);
            else // under FF, we get one more mouse-down from the double-click
                args.points = this._points.slice(0, this._points.length-1-2*3);
        } else {
            args.points = this._points.slice(0);
        }
        this.callServerAsync(args);
    },        

    onCallbackReceived : function(args) {
        this.updateView();
    },</pre>
<p>You can find the VS2008 project here: <a href="http://blogs.ilog.com/netvisu/wp-content/uploads/2008/06/ajaxbeziersample.zip" title="AjaxBezierSample VS2008 Project">AjaxBezierSample VS2008 Project</a>. Do not hesitate to look at the MakeCurveBehavior.js file to see how the the primitives points are updated.</p>
<p>The purpose of this implementation being a tutorial, many improvements are still to be done. For example, you could add properties to be able to customize the ghost rendering (the stroke color, the stroke style, etc.), an optional PostBack behavior (see ViewBehavior.doPostBack() method), additional editing capabilities (add/supress points or closed curves support).</p>
<p>As you can see, writing a new interactor for an AjaxDiagramView is essentially a client-side task. Fortunately, the Microsoft JavaScript Library and the ILOG.Diagrammer.Web.UI.ViewBehavior class provide a rich set of functionalities and services that make the JavaScript implementation easier and poweful. Also, the use of asynchronous callbacks to handle the interaction allows a very smooth user experience avoiding the annoying cost of a PostBack.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.ilog.com/netvisu/2008/06/20/create-bezier-curve-in-an-ajaxdiagramview-part-2/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
