{"id":2896,"date":"2024-07-21T09:37:49","date_gmt":"2024-07-21T09:37:49","guid":{"rendered":"https:\/\/mindfusion.eu\/blog\/?p=2896"},"modified":"2024-07-21T09:40:45","modified_gmt":"2024-07-21T09:40:45","slug":"custom-diagram-canvas-pagination","status":"publish","type":"post","link":"https:\/\/mindfusion.dev\/blog\/custom-diagram-canvas-pagination\/","title":{"rendered":"Custom diagram canvas pagination"},"content":{"rendered":"\n<p>In this post we\u2019ll show how to implement Visio-like dynamic pagination of the diagram canvas, expanding or shrinking it while users draw nodes interactively, and rendering custom page borders. This is demonstrated using MindFusion Windows Forms Diagram control, but equivalent APIs are provided by MindFusion diagramming libraries for other platforms.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Start by creating a new WinForms project and adding the MindFusion.Diagramming package in NuGet Package Manager. After installing the package, add DiagramView and Diagram instances to the form, setting view&#8217;s Diagram property to the form&#8217;s member.<\/p>\n\n\n\n<p>Add the following fields to the form class to keep track of the current pages:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SizeF pageSize = new SizeF(150, 100);\nint pageCols = 1;\nint pageRows = 1;<\/code><\/pre>\n\n\n\n<p>In form&#8217;s Load event handler, set the following properties to let us control the canvas size manually, and render the area outside diagram.Bounds in a different color:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>diagram.ExteriorBrush = new SolidBrush(Color.Gray);\ndiagram.AutoResize = AutoResize.None;\ndiagram.Bounds = new RectangleF(new PointF(), pageSize);\ndiagram.RestrictItemsToBounds = RestrictToBounds.NoRestriction;<\/code><\/pre>\n\n\n\n<p>Handle NodeCreating and NodeModifying events in order to add or remove pages while users draw on the canvas. Handle DrawForeground event to draw custom page borders:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>diagram.NodeCreating += OnNodeCreating;\ndiagram.NodeModifying += OnNodeModifying;\ndiagram.DrawForeground += OnDrawForeground;<\/code><\/pre>\n\n\n\n<p>The pages are arranged in a grid that fits the rectangle returned by GetContentBounds method:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void ResizePageGrid(DiagramNode newNode = null)\n{\n\tvar contentBounds = diagram.GetContentBounds(false, true);\n\tif (newNode != null)\n\t{\n\t\tcontentBounds = RectangleF.Union(\n\t\t\tcontentBounds, newNode.Bounds);\n\t}\n\n\tint newPageCols = 1 + (int)(contentBounds.Right \/ pageSize.Width);\n\tint newPageRows = 1 + (int)(contentBounds.Bottom \/ pageSize.Height);\n\n\tif (pageCols != newPageCols || pageRows != newPageRows)\n\t{\n\t\tpageCols = newPageCols;\n\t\tpageRows = newPageRows;\n\n\t\tdiagram.Bounds = new RectangleF(\n\t\t\t0, 0, pageSize.Width * pageCols, pageSize.Height * pageRows);\n\n\t\tdiagramView.RecreateCacheImage();\n\t\tdiagramView.Refresh();\n\t}\n}\n\nvoid OnNodeCreating(object sender, NodeValidationEventArgs e)\n{\n\tResizePageGrid(e.Node);\n}\n\nvoid OnNodeModifying(object sender, NodeValidationEventArgs e)\n{\n\tResizePageGrid();\n}<\/code><\/pre>\n\n\n\n<p>Page borders are drawn by looping over the grid rows and columns:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void OnDrawForeground(object sender, DiagramEventArgs e)\n{\n\tvar pen = new System.Drawing.Pen(Color.Black)\n\t{\n\t\tWidth = 0,\n\t\tDashStyle = System.Drawing.Drawing2D.DashStyle.Dot\n\t};\n\n\t\/\/ draw vertical page borders\n\tfor (int c = 0; c &lt;= pageCols; c++)\n\t{\n\t\tfloat x = c * pageSize.Width;\n\t\te.Graphics.DrawLine(\n\t\t\tpen, x, 0, x, diagram.Bounds.Height);\n\t}\n\n\t\/\/ draw horizontal page borders\n\tfor (int r = 0; r &lt;= pageRows; r++)\n\t{\n\t\tfloat y = r * pageSize.Height;\n\t\te.Graphics.DrawLine(\n\t\t\tpen, 0, y, diagram.Bounds.Width, y);\n\t}\n\n\tpen.Dispose();\n}<\/code><\/pre>\n\n\n\n<p>Now if you drag a node outside the initial page boundaries, the page grid will expand to accommodate the new node position:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/mindfusion.dev\/_samples\/custom_paging.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>The complete sample project is available for download here:<\/p>\n\n\n\n<p><a href=\"https:\/\/mindfusion.dev\/_samples\/CustomPaging.zip\">https:\/\/mindfusion.dev\/_samples\/CustomPaging.zip<\/a><\/p>\n\n\n\n<p>An alternative way to render pages could be to create a cell for each page in the built-in LaneGrid object. Finally, note that if you don&#8217;t need to display all pages on the same canvas, you can use the TabbedDiagramView control to show a multi-page DiagramDocument object.<\/p>\n\n\n\n<p>Enjoy!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post we\u2019ll show how to implement Visio-like dynamic pagination of the diagram canvas, expanding or shrinking it while users draw nodes interactively, and rendering custom page borders. This is demonstrated using MindFusion Windows Forms Diagram control, but equivalent &hellip; <a href=\"https:\/\/mindfusion.dev\/blog\/custom-diagram-canvas-pagination\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[2],"tags":[69,3,29],"class_list":["post-2896","post","type-post","status-publish","format-standard","hentry","category-product-releases","tag-control","tag-diagram","tag-winforms"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3RlKs-KI","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2896","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/comments?post=2896"}],"version-history":[{"count":3,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2896\/revisions"}],"predecessor-version":[{"id":2900,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2896\/revisions\/2900"}],"wp:attachment":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/media?parent=2896"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/categories?post=2896"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/tags?post=2896"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}