Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / WPF

Simple Visual Studio like Pane Resizing, Docking, and Collapsing

Rate me:
Please Sign up or sign in to vote.
4.94/5 (15 votes)
28 Feb 2013CPOL13 min read 67.2K   5.9K   63  
Learn to create a simple custom control that allows users to dock.
  • DockableVsExample-noexe.zip
    • DockableVsExample
      • .cov
      • _ReSharper.DockableVsExample
        • AspFileDataCache.dat
        • BuildScriptCache
          • .crc
          • .version
          • 2
            • 2b968c50.dat
        • ConditionalNames
          • .crc
          • .version
          • 2
            • 2b968c50.dat
        • JavaScriptCache
          • .crc
          • .version
          • 2
            • 2b968c50.dat
        • JSTest
          • .crc
          • .version
        • ModuleIds.xml
        • MVC
          • .crc
          • .version
        • NamedArguments
          • .crc
          • .version
          • 2
            • 2b968c50.dat
        • PersistenIdIndex.bin
        • RecentItems
          • RecentFiles.dat
        • Resources
          • .crc
          • .version
          • 0
            • 1d145dd1.dat
        • SymbolCache.bin
        • TagPrefixes
          • .crc
          • .version
        • TodoItems
          • .crc
          • .version
          • 2
            • 2b968c50.dat
        • WebSymbols
          • .crc
          • .version
        • WordIndex
          • .crc
          • .version
          • 2
            • 2b968c50.dat
        • XmlIndex
          • Accessibility.xml
            • 59F683E5.bin
            • C7A6AAD7.bin
          • Microsoft.Build.Framework.4.0.0.0.Nullness.Generated.xml
            • 91BD6FD3.bin
          • Microsoft.Build.Framework.xml
            • 5B4D04B5.bin
          • Microsoft.Build.Tasks.v4.0.4.0.0.0.Nullness.Generated.xml
            • AB623953.bin
          • Microsoft.Build.Tasks.v4.0.xml
            • 390E8A25.bin
          • Microsoft.Build.Utilities.v4.0.4.0.0.0.Nullness.Generated.xml
            • 07D57913.bin
          • Microsoft.Build.Utilities.v4.0.xml
            • 1A2D939D.bin
          • Microsoft.CSharp.4.0.0.0.Nullness.Generated.xml
            • 10F25633.bin
          • Microsoft.CSharp.xml
            • 1D407EB8.bin
          • Microsoft.VisualC.xml
            • 2F48D914.bin
          • mscorlib.4.0.0.0.Contracts.xml
            • 0DED0883.bin
          • mscorlib.4.0.0.0.Interfaces.Nullness.Generated.xml
            • 620DC5CB.bin
          • mscorlib.4.0.0.0.Nullness.Generated.xml
            • 772ECBB3.bin
          • mscorlib.4.0.0.0.Pure.xml
            • 6572C670.bin
          • mscorlib.I18n.xml
            • 366D6FC8.bin
          • mscorlib.Nullness.Manual.xml
            • A029C282.bin
          • mscorlib.ValueFlow.xml
            • 4E59B0BF.bin
          • mscorlib.xml
            • 05998BE8.bin
            • 743ADB6C.bin
            • 80BFF39E.bin
          • PresentationCore.4.0.0.0.Nullness.Generated.xml
            • 6892EAF3.bin
          • PresentationCore.xml
            • 6EEF5274.bin
            • 6F6FC046.bin
          • PresentationFramework.4.0.0.0.Nullness.Generated.xml
            • 5BD919D3.bin
          • PresentationFramework.4.0.0.0.Xaml.xml
            • 86321E7A.bin
          • PresentationFramework.Nullness.Manual.xml
            • 541B7CA2.bin
          • PresentationFramework.xml
            • 75940F93.bin
            • B6BE5621.bin
          • PresentationUI.4.0.0.0.Nullness.Generated.xml
            • DBA70613.bin
          • ReachFramework.4.0.0.0.Nullness.Generated.xml
            • A1074D33.bin
          • ReachFramework.xml
            • 450C246A.bin
            • CF31C018.bin
          • SMDiagnostics.4.0.0.0.Nullness.Generated.xml
            • 8E9945D3.bin
          • System.4.0.0.0.Contracts.xml
            • 7458FC03.bin
          • System.4.0.0.0.Nullness.Generated.xml
            • 5304AF33.bin
          • System.4.0.0.0.Pure.xml
            • 403889F0.bin
          • System.ComponentModel.DataAnnotations.4.0.0.0.Nullness.Generated.xml
            • EB11BC93.bin
          • System.ComponentModel.DataAnnotations.I18n.xml
            • E1E89968.bin
          • System.ComponentModel.DataAnnotations.xml
            • B9A8C76A.bin
          • System.Configuration.4.0.0.0.Contracts.xml
            • 8AA99CC3.bin
          • System.Configuration.4.0.0.0.Nullness.Generated.xml
            • 5C04A9F3.bin
          • System.Configuration.4.0.0.0.Pure.xml
            • A30FD330.bin
          • System.Configuration.Install.4.0.0.0.Contracts.xml
            • F6158D63.bin
          • System.Configuration.Install.4.0.0.0.Nullness.Generated.xml
            • 28353B53.bin
          • System.Configuration.Install.xml
            • 7FB1C71F.bin
          • System.Configuration.xml
            • 092A1070.bin
            • 3BFF1442.bin
          • System.Core.4.0.0.0.Contracts.xml
            • 9A69C6A3.bin
          • System.Core.4.0.0.0.Nullness.Generated.xml
            • 8E5F4293.bin
          • System.Core.4.0.0.0.Pure.xml
            • D7464B10.bin
          • System.Core.LinqTunnel.xml
            • 63F26974.bin
          • System.Core.Nullness.Manual.xml
            • 31BDD0E2.bin
          • System.Core.xml
            • 11686E5B.bin
            • 1C6B8C69.bin
          • System.Data.4.0.0.0.Contracts.xml
            • 68A7E423.bin
          • System.Data.4.0.0.0.Nullness.Generated.xml
            • 7A169013.bin
          • System.Data.4.0.0.0.Pure.xml
            • 595BF890.bin
          • System.Data.DataSetExtensions.4.0.0.0.Nullness.Generated.xml
            • DB866913.bin
          • System.Data.DataSetExtensions.I18n.xml
            • B16CE5E8.bin
          • System.Data.DataSetExtensions.xml
            • 561D2A14.bin
          • System.Data.Entity.4.0.0.0.Nullness.Generated.xml
            • 30E64393.bin
          • System.Data.Entity.xml
            • 9398E105.bin
          • System.Data.I18n.xml
            • 51BDCCE8.bin
          • System.Data.OracleClient.4.0.0.0.Nullness.Generated.xml
            • 9BDAABD3.bin
          • System.Data.OracleClient.xml
            • 27DDCE31.bin
          • System.Data.SqlXml.4.0.0.0.Nullness.Generated.xml
            • B9F432D3.bin
          • System.Data.SqlXml.xml
            • 0CFF57DB.bin
            • 48CF6F29.bin
          • System.Data.xml
            • 2535F582.bin
            • 7BF6DA70.bin
          • System.Deployment.4.0.0.0.Nullness.Generated.xml
            • B159D593.bin
          • System.Deployment.xml
            • 566A1F4B.bin
            • CC017739.bin
          • System.Design.4.0.0.0.Nullness.Generated.xml
            • 97CA2CD3.bin
          • System.Design.xml
            • 66D504B2.bin
          • System.DirectoryServices.4.0.0.0.Nullness.Generated.xml
            • 494E7693.bin
          • System.DirectoryServices.Protocols.4.0.0.0.Nullness.Generated.xml
            • CFA46BF3.bin
          • System.DirectoryServices.Protocols.xml
            • A1B5E32C.bin
          • System.DirectoryServices.xml
            • 14397267.bin
            • 88DA6355.bin
          • System.Drawing.4.0.0.0.Contracts.xml
            • 90ED1C03.bin
          • System.Drawing.4.0.0.0.Nullness.Generated.xml
            • 283CCF33.bin
          • System.Drawing.4.0.0.0.Pure.xml
            • 07B8A9F0.bin
          • System.Drawing.Design.4.0.0.0.Nullness.Generated.xml
            • EFA69853.bin
          • System.Drawing.Design.xml
            • E232227C.bin
          • System.Drawing.xml
            • 2F425360.bin
            • CD562AD2.bin
          • System.Dynamic.4.0.0.0.Nullness.Generated.xml
            • 8CC52453.bin
          • System.EnterpriseServices.4.0.0.0.Nullness.Generated.xml
            • C42E9193.bin
          • System.EnterpriseServices.xml
            • 484CBB5B.bin
            • BC835E69.bin
          • System.I18n.xml
            • E767B348.bin
          • System.Nullness.Manual.xml
            • AC02D602.bin
          • System.Numerics.4.0.0.0.Nullness.Generated.xml
            • 0D729213.bin
          • System.Numerics.xml
            • 4231948A.bin
            • F65D6778.bin
          • System.Printing.4.0.0.0.Nullness.Generated.xml
            • A17A3513.bin
          • System.Printing.xml
            • 703E5A63.bin
            • 9376C751.bin
          • System.Runtime.Caching.4.0.0.0.Nullness.Generated.xml
            • 8BB7FA53.bin
          • System.Runtime.Caching.xml
            • 6E34C19B.bin
          • System.Runtime.DurableInstancing.4.0.0.0.Nullness.Generated.xml
            • 94C6B993.bin
          • System.Runtime.DurableInstancing.xml
            • 3BFDDE45.bin
            • 952CDDB7.bin
          • System.Runtime.Remoting.4.0.0.0.Nullness.Generated.xml
            • 5A03BD53.bin
          • System.Runtime.Remoting.xml
            • 3CA70F41.bin
            • 99D48EF3.bin
          • System.Runtime.Serialization.4.0.0.0.Nullness.Generated.xml
            • 4774B3B3.bin
          • System.Runtime.Serialization.Attributes.xml
            • E749FA69.bin
          • System.Runtime.Serialization.Formatters.Soap.2.0.0.0.Contracts.xml
            • 6A729305.bin
          • System.Runtime.Serialization.Formatters.Soap.4.0.0.0.Contracts.xml
            • 4C2FB483.bin
          • System.Runtime.Serialization.Formatters.Soap.4.0.0.0.Nullness.Generated.xml
            • F932F7B3.bin
          • System.Runtime.Serialization.Formatters.Soap.xml
            • AC344D82.bin
            • C8E5DC30.bin
          • System.Runtime.Serialization.xml
            • 014E8BDC.bin
            • B677C06E.bin
          • System.Security.4.0.0.0.Contracts.xml
            • 203E41A3.bin
          • System.Security.4.0.0.0.Nullness.Generated.xml
            • F66E1D93.bin
          • System.Security.4.0.0.0.Pure.xml
            • 3CA1E610.bin
          • System.Security.xml
            • 02B7D304.bin
            • 55841E76.bin
          • System.ServiceProcess.4.0.0.0.Nullness.Generated.xml
            • 359B1C13.bin
          • System.ServiceProcess.xml
            • 2335E116.bin
          • System.Transactions.4.0.0.0.Nullness.Generated.xml
            • 3921BF93.bin
          • System.Transactions.xml
            • 377E8A05.bin
            • A0E212F7.bin
          • System.Web.4.0.0.0.Contracts.xml
            • 9CAD0083.bin
          • System.Web.4.0.0.0.Nullness.Generated.xml
            • 4965C3B3.bin
          • System.Web.4.0.0.0.Pure.xml
            • 4657BE70.bin
          • System.Web.ApplicationServices.4.0.0.0.Nullness.Generated.xml
            • 3969B1B3.bin
          • System.Web.ApplicationServices.xml
            • 331D36EA.bin
          • System.Web.Attributes.xml
            • C91B0A69.bin
          • System.Web.I18n.xml
            • DDDA67C8.bin
          • System.Web.RegularExpressions.xml
            • B6E517C5.bin
          • System.Web.Services.4.0.0.0.Nullness.Generated.xml
            • 30597093.bin
          • System.Web.Services.Attributes.xml
            • 336EB089.bin
          • System.Web.Services.xml
            • 057956D0.bin
          • System.Web.xml
            • 7F630C15.bin
            • C4EB8CF0.bin
          • System.Windows.Forms.4.0.0.0.Contracts.xml
            • 0AA1AF83.bin
          • System.Windows.Forms.4.0.0.0.Nullness.Generated.xml
            • E30F52B3.bin
          • System.Windows.Forms.4.0.0.0.Pure.xml
            • FDE30D70.bin
          • System.Windows.Forms.I18n.xml
            • 4286B6C8.bin
          • System.Windows.Forms.Manual.xml
            • 4EEF7F3C.bin
          • System.Windows.Forms.xml
            • 13FFA7C6.bin
            • 628A07B4.bin
          • System.Windows.Input.Manipulations.4.0.0.0.Nullness.Generated.xml
            • FDC406D3.bin
          • System.Windows.Input.Manipulations.xml
            • 2DA32DB7.bin
            • DB2249C5.bin
          • System.Xaml.4.0.0.0.Nullness.Generated.xml
            • A8037753.bin
          • System.Xaml.xml
            • B4FB056A.bin
            • C4D1BFD8.bin
          • System.Xml.4.0.0.0.Contracts.xml
            • 53D95363.bin
          • System.Xml.4.0.0.0.Nullness.Generated.xml
            • DD97C153.bin
          • System.Xml.4.0.0.0.Pure.xml
            • 5A1C7B50.bin
          • System.Xml.Attributes.xml
            • 09EED2C9.bin
          • System.Xml.I18n.xml
            • 8B551FA8.bin
          • System.Xml.Linq.4.0.0.0.Contracts.xml
            • 0FA00AA3.bin
          • System.Xml.Linq.4.0.0.0.Nullness.Generated.xml
            • 0EE20693.bin
          • System.Xml.Linq.4.0.0.0.Pure.xml
            • 9C820F10.bin
          • System.Xml.Linq.I18n.xml
            • A5756368.bin
          • System.Xml.Linq.xml
            • 315B32BF.bin
            • AD7A27CD.bin
          • System.Xml.xml
            • 48B5EA79.bin
            • EAFF084B.bin
          • System.xml
            • 13EB449C.bin
            • 74BB9F68.bin
            • C3B3EEEE.bin
          • UIAutomationProvider.4.0.0.0.Nullness.Generated.xml
            • 0F77E253.bin
          • UIAutomationProvider.xml
            • 0476AD9B.bin
          • UIAutomationTypes.4.0.0.0.Nullness.Generated.xml
            • D2732553.bin
          • UIAutomationTypes.xml
            • 822993E3.bin
            • AB13DD51.bin
          • WindowsBase.4.0.0.0.Nullness.Generated.xml
            • 08F51D53.bin
          • WindowsBase.4.0.0.0.Pure.xml
            • 2D08D750.bin
          • WindowsBase.xml
            • 2F308F93.bin
            • 30274CA1.bin
      • Controls
      • DockableVsExample.sln
      • DockableVsExample
  • DockableVsExample.zip
    • coverity.config
    • desktop-settings.xml
    • AspFileDataCache.dat
    • .crc
    • .version
    • 2b968c50.dat
    • .crc
    • .version
    • 2b968c50.dat
    • .crc
    • .version
    • 2b968c50.dat
    • JbPdbInfo
      • .crc
      • .version
      • ModuleIds.xml
      • .crc
      • .version
      • .crc
      • .version
      • 2b968c50.dat
      • PersistenIdIndex.bin
      • RecentFiles.dat
      • .crc
      • .version
      • 1d145dd1.dat
      • SymbolCache.bin
      • .crc
      • .version
      • .crc
      • .version
      • 2b968c50.dat
      • .crc
      • .version
      • .crc
      • .version
      • 2b968c50.dat
      • 59F683E5.bin
      • C7A6AAD7.bin
      • 91BD6FD3.bin
      • 5B4D04B5.bin
      • AB623953.bin
      • 390E8A25.bin
      • 07D57913.bin
      • 1A2D939D.bin
      • 10F25633.bin
      • 1D407EB8.bin
      • 2F48D914.bin
      • 0DED0883.bin
      • 620DC5CB.bin
      • 772ECBB3.bin
      • 6572C670.bin
      • 366D6FC8.bin
      • A029C282.bin
      • 4E59B0BF.bin
      • 05998BE8.bin
      • 743ADB6C.bin
      • 80BFF39E.bin
      • 6892EAF3.bin
      • 6EEF5274.bin
      • 6F6FC046.bin
      • 5BD919D3.bin
      • 86321E7A.bin
      • 541B7CA2.bin
      • 75940F93.bin
      • B6BE5621.bin
      • DBA70613.bin
      • A1074D33.bin
      • 450C246A.bin
      • CF31C018.bin
      • 8E9945D3.bin
      • 7458FC03.bin
      • 5304AF33.bin
      • 403889F0.bin
      • EB11BC93.bin
      • E1E89968.bin
      • B9A8C76A.bin
      • 8AA99CC3.bin
      • 5C04A9F3.bin
      • A30FD330.bin
      • F6158D63.bin
      • 28353B53.bin
      • 7FB1C71F.bin
      • 092A1070.bin
      • 3BFF1442.bin
      • 9A69C6A3.bin
      • 8E5F4293.bin
      • D7464B10.bin
      • 63F26974.bin
      • 31BDD0E2.bin
      • 11686E5B.bin
      • 1C6B8C69.bin
      • 68A7E423.bin
      • 7A169013.bin
      • 595BF890.bin
      • DB866913.bin
      • B16CE5E8.bin
      • 561D2A14.bin
      • 30E64393.bin
      • 9398E105.bin
      • 51BDCCE8.bin
      • 9BDAABD3.bin
      • 27DDCE31.bin
      • B9F432D3.bin
      • 0CFF57DB.bin
      • 48CF6F29.bin
      • 2535F582.bin
      • 7BF6DA70.bin
      • B159D593.bin
      • 566A1F4B.bin
      • CC017739.bin
      • 97CA2CD3.bin
      • 66D504B2.bin
      • 494E7693.bin
      • CFA46BF3.bin
      • A1B5E32C.bin
      • 14397267.bin
      • 88DA6355.bin
      • 90ED1C03.bin
      • 283CCF33.bin
      • 07B8A9F0.bin
      • EFA69853.bin
      • E232227C.bin
      • 2F425360.bin
      • CD562AD2.bin
      • 8CC52453.bin
      • C42E9193.bin
      • 484CBB5B.bin
      • BC835E69.bin
      • E767B348.bin
      • AC02D602.bin
      • 0D729213.bin
      • 4231948A.bin
      • F65D6778.bin
      • A17A3513.bin
      • 703E5A63.bin
      • 9376C751.bin
      • 8BB7FA53.bin
      • 6E34C19B.bin
      • 94C6B993.bin
      • 3BFDDE45.bin
      • 952CDDB7.bin
      • 5A03BD53.bin
      • 3CA70F41.bin
      • 99D48EF3.bin
      • 4774B3B3.bin
      • E749FA69.bin
      • 6A729305.bin
      • 4C2FB483.bin
      • F932F7B3.bin
      • AC344D82.bin
      • C8E5DC30.bin
      • 014E8BDC.bin
      • B677C06E.bin
      • 203E41A3.bin
      • F66E1D93.bin
      • 3CA1E610.bin
      • 02B7D304.bin
      • 55841E76.bin
      • 359B1C13.bin
      • 2335E116.bin
      • 3921BF93.bin
      • 377E8A05.bin
      • A0E212F7.bin
      • 9CAD0083.bin
      • 4965C3B3.bin
      • 4657BE70.bin
      • 3969B1B3.bin
      • 331D36EA.bin
      • C91B0A69.bin
      • DDDA67C8.bin
      • B6E517C5.bin
      • 30597093.bin
      • 336EB089.bin
      • 057956D0.bin
      • 7F630C15.bin
      • C4EB8CF0.bin
      • 0AA1AF83.bin
      • E30F52B3.bin
      • FDE30D70.bin
      • 4286B6C8.bin
      • 4EEF7F3C.bin
      • 13FFA7C6.bin
      • 628A07B4.bin
      • FDC406D3.bin
      • 2DA32DB7.bin
      • DB2249C5.bin
      • A8037753.bin
      • B4FB056A.bin
      • C4D1BFD8.bin
      • 53D95363.bin
      • DD97C153.bin
      • 5A1C7B50.bin
      • 09EED2C9.bin
      • 8B551FA8.bin
      • 0FA00AA3.bin
      • 0EE20693.bin
      • 9C820F10.bin
      • A5756368.bin
      • 315B32BF.bin
      • AD7A27CD.bin
      • 48B5EA79.bin
      • EAFF084B.bin
      • 13EB449C.bin
      • 74BB9F68.bin
      • C3B3EEEE.bin
      • 0F77E253.bin
      • 0476AD9B.bin
      • D2732553.bin
      • 822993E3.bin
      • AB13DD51.bin
      • 08F51D53.bin
      • 2D08D750.bin
      • 2F308F93.bin
      • 30274CA1.bin
      • bin
      • DockableVsExample.sln
      • DockableVsExample.suo
      • App.xaml
      • App.xaml.cs
      • Controls.dll
      • Controls.pdb
      • DockableVsExample.exe
      • DockableVsExample.pdb
      • DockableVsExample.vshost.exe
      • DockableVsExample.vshost.exe.manifest
      • DockableVsExample.csproj
      • Home-icon.png
      • MyIcon.ico
      • Next-icon.png
      • MainWindow.xaml
      • MainWindow.xaml.cs
      • obj
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Controls
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Controls"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Controls;assembly=Controls"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:LayeredGrid/>
    ///
    /// </summary>
    [TemplatePart(Name = "PART_MasterGrid", Type = typeof(Grid))]
    [TemplatePart(Name = "PART_RightCntl", Type = typeof(StackPanel))]
    [TemplatePart(Name = "PART_LeftCntl", Type = typeof(StackPanel))]
    [TemplatePart(Name = "PART_BottomCntl", Type = typeof(StackPanel))]
    public class LayeredGrid : ContentControl
    {
        #region fields
        private Grid PART_MasterGrid;
        private StackPanel PART_RightCntl;
        private StackPanel PART_LeftCntl;
        private StackPanel PART_BottomCntl;
        private DockPanel PART_ParentPanel;
        private readonly ObservableCollection<Layer> _aValues = new ObservableCollection<Layer>();
        private readonly List<GridnFloatingBtnCombo> _columnLayers = new List<GridnFloatingBtnCombo>();
        private readonly List<GridnFloatingBtnCombo> _rowLayers = new List<GridnFloatingBtnCombo>();
        private const string ColumnStr = "column";
        private const string RowStr = "row";
        private const string LayerStr = "Layer";
        private const string PinStr = "btn";
        #endregion

        #region layer grid, button btn, columns and rows definition holder class
        private class GridnFloatingBtnCombo
        {
            public readonly Grid Grid;
            public readonly Button Btn;
            public readonly List<ColumnDefinition> ColumnDefinitions;
            public readonly List<Layer.LayerColumnLocation> ColumnLocations;
            public readonly List<RowDefinition> RowDefinitions;
            public int MainContentLocation { get; private set; }

            public GridnFloatingBtnCombo(Grid grid, Button btn)
            {
                Grid = grid;
                Btn = btn;
                ColumnDefinitions = new List<ColumnDefinition>();
                RowDefinitions = new List<RowDefinition>();
                ColumnLocations = new List<Layer.LayerColumnLocation>();
                MainContentLocation = 1;
            }

            public void MainContentPositionIncrement()
            {
                MainContentLocation++;
            }

            public void MainContentPositionDecrement()
            {
                if (MainContentLocation > 1)
                    MainContentLocation--;
            }

        }
        #endregion

        #region properties and DPs
        private static readonly DependencyPropertyKey LayersPropertyKey = DependencyProperty.RegisterReadOnly("Layers",
                                                                                                               typeof(
                                                                                                                       ObservableCollection
                                                                                                                       <Layer>),
                                                                                                               typeof(LayeredGrid),
                                                                                                               new PropertyMetadata(null));

        public static readonly DependencyProperty LayersProperty = LayersPropertyKey.DependencyProperty;
        public ObservableCollection<Layer> Layers
        {
            get { return (ObservableCollection<Layer>)GetValue(LayersProperty); }
            set { SetValue(LayersProperty, value); }
        }

        #endregion

        #region constructor
        static LayeredGrid()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(LayeredGrid), new FrameworkPropertyMetadata(typeof(LayeredGrid)));

        }

        /// <summary>
        /// Initializes the Layers collection
        /// </summary>
        public LayeredGrid()
        {
            SetValue(LayersPropertyKey, _aValues);
        }
        #endregion

        #region Methods

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            //get the part controls 
            PART_MasterGrid = GetTemplateChild("PART_MasterGrid") as Grid;
            PART_RightCntl = GetTemplateChild("PART_RightCntl") as StackPanel;
            PART_LeftCntl = GetTemplateChild("PART_LeftCntl") as StackPanel;
            PART_BottomCntl = GetTemplateChild("PART_BottomCntl") as StackPanel;
            PART_ParentPanel = GetTemplateChild("PART_ParentPanel") as DockPanel;
            //verify master grid exist
            if (PART_MasterGrid == null)
                return;
            //setup parent grid
            var parentGrid = new Grid();
            SetUpParentGrid(parentGrid);
            //set up layers
            var layer0 = Layers.FirstOrDefault(x => x.Level == 0);
            if (layer0 == null)
                return;

            var columnLayers =
                Layers.Select(x => x).Where(x => x.Level > 0 && x.Orientation == Layer.LayerOrientation.Column).OrderBy(
                    x => x.Level);
            var rowLayers =
                Layers.Select(x => x).Where(x => x.Level > 0 && x.Orientation == Layer.LayerOrientation.Row).OrderBy(x => x.Level);
            var item = SetupLayer0(layer0,
                                   columnLayers,
                                   rowLayers.Count());
            parentGrid.Children.Add(item);
            Grid.SetRow(item, 0);
            //setup the column grid layers
            if (columnLayers.Any())
            {
                foreach (var layer in columnLayers)
                {
                    SetupColumnLayers(parentGrid, layer, columnLayers.Count());
                }
            }
            //setup the row grid layers
            if (rowLayers.Any())
            {
                foreach (var layer in rowLayers)
                {
                    SetupRowLayers(parentGrid, layer, rowLayers.Count());
                }
            }

            //add parent grid to master grid
            PART_MasterGrid.Children.Add(parentGrid);
            Grid.SetRow(parentGrid, 0);
        }

        private static void SetUpParentGrid(Grid parent)
        {
            var row1 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
            var row2 = new RowDefinition { Height = GridLength.Auto };
            parent.RowDefinitions.Add(row1);
            parent.RowDefinitions.Add(row2);
        }

        private Grid SetupLayer0(Layer layer0, IEnumerable<Layer> columnLayers, int numberofRows)
        {
            var grid = new Grid { Name = ColumnStr + LayerStr + layer0.Level };
            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
            grid.RowDefinitions.Add(new RowDefinition());
            grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
            if (layer0.Content != null)
                grid.Children.Add(layer0.Content);
            if (layer0.Content != null)
                Grid.SetColumn(layer0.Content, 1);
            grid.MouseEnter += (o, e) =>
            {
                for (var i = 1; i < _columnLayers.Count; i++)
                {
                    if (_columnLayers[i].Btn.Visibility == Visibility.Visible)
                    {
                        _columnLayers[i].Grid.Visibility = Visibility.Collapsed;
                    }
                }

                for (var i = 1; i < _rowLayers.Count; i++)
                {
                    if (_rowLayers[i].Btn.Visibility == Visibility.Visible)
                    {
                        _rowLayers[i].Grid.Visibility = Visibility.Collapsed;
                    }
                }
            };
            //layer zero does not need a pin
            var gnb = new GridnFloatingBtnCombo(grid, null);
            if (columnLayers.Any())
            {
                var list = columnLayers.ToList();
                for (int i = 0; i < columnLayers.Count(); i++)
                {
                    gnb.ColumnDefinitions.Add(new ColumnDefinition { SharedSizeGroup = ColumnStr + (i + 1) + list[i].ColumnLocation, Width = GridLength.Auto });
                    gnb.ColumnLocations.Add(list[i].ColumnLocation);
                }
            }
            if (numberofRows > 0)
            {
                for (int i = 0; i < numberofRows; i++)
                {
                    gnb.RowDefinitions.Add(new RowDefinition { SharedSizeGroup = RowStr + (i + 1), Height = GridLength.Auto });
                }
            }
            _columnLayers.Add(gnb);
            _rowLayers.Add(gnb);
            return grid;
        }

        private void SetupColumnLayers(Grid parentGrid, Layer layer, int columnLayerCnt)
        {
            var grid = new Grid
            {
                Name = ColumnStr + LayerStr + layer.Level,
                Visibility = Visibility.Collapsed
            };
            grid.ColumnDefinitions.Add(new ColumnDefinition
            {
                SharedSizeGroup = layer.ColumnLocation == Layer.LayerColumnLocation.Left
                                                                            ? ColumnStr + layer.Level + layer.ColumnLocation
                                                                            : null,
                Width = GridLength.Auto
            });
            grid.ColumnDefinitions.Add(new ColumnDefinition
            {
                Width = new GridLength(1, GridUnitType.Star)
            });
            grid.ColumnDefinitions.Add(new ColumnDefinition
            {
                SharedSizeGroup = layer.ColumnLocation == Layer.LayerColumnLocation.Right
                                                                            ? ColumnStr + layer.Level + layer.ColumnLocation
                                                                            : null,
                Width = GridLength.Auto
            });
            var internalGrid = new Grid();
            internalGrid.RowDefinitions.Add(new RowDefinition
            {
                Height = GridLength.Auto
            });
            internalGrid.RowDefinitions.Add(new RowDefinition());
            internalGrid.Background = (RadialGradientBrush)PART_MasterGrid.FindResource("myColorfulLabelBrush");
            grid.Children.Add(internalGrid);
            Grid.SetColumn(internalGrid,
                           layer.ColumnLocation == Layer.LayerColumnLocation.Left ? 0 : 2
                          );
            var dockpanel = new DockPanel();
            internalGrid.Children.Add(dockpanel);
            Grid.SetRow(dockpanel, 0);
            var btn = new Button
            {
                Name = ColumnStr + PinStr + layer.Level,
                Width = 28.0,
                Background = Brushes.Transparent,
                BorderBrush = Brushes.Transparent,
                Style = (Style)PART_MasterGrid.FindResource("buttonStyle"),
                Content = new Path
                {
                    Stroke = Brushes.Black,
                    Fill = Brushes.Gold,
                    StrokeThickness = 1,
                    Stretch = Stretch.Fill,
                    Width = 9.0,
                    Height = 15,
                    Data = PinPathgeometry()
                }

            };
            dockpanel.Children.Add(btn);
            DockPanel.SetDock(btn, Dock.Right);
            btn.Click += (o, e) =>
            {
                var level = layer.Level;
                var item = _columnLayers[level].Btn;
                if (item.Visibility == Visibility.Collapsed)
                    ColumnUndockPane(level, o as Button);
                else
                    ColumnDockPane(level, o as Button);
            };
            var textblock = new TextBlock
            {
                Padding = new Thickness(8),
                TextTrimming = TextTrimming.CharacterEllipsis,
                Foreground = Brushes.Gold,
                Text = layer.Name
            };
            dockpanel.Children.Add(textblock);
            DockPanel.SetDock(textblock, Dock.Left);
            if (layer.Content != null)
            {
                internalGrid.Children.Add(layer.Content);
                Grid.SetRow(layer.Content, 1);
            }
            var gridSplitter = new GridSplitter
            {
                Width = 2,
                Background = Brushes.CadetBlue,
                HorizontalAlignment = layer.ColumnLocation == Layer.LayerColumnLocation.Right
                                                                            ? HorizontalAlignment.Left
                                                                            : HorizontalAlignment.Right
            };
            grid.Children.Add(gridSplitter);
            Grid.SetColumn(gridSplitter,
                           layer.ColumnLocation == Layer.LayerColumnLocation.Right ? 2 : 0
                          );
            grid.MouseEnter += (o, e) =>
            {
                var level = layer.Level;
                for (var i = (level + 1); i < _columnLayers.Count; i++)
                {
                    if (_columnLayers[i].Btn.Visibility == Visibility.Visible)
                        _columnLayers[i].Grid.Visibility = Visibility.Collapsed;
                }
            };
            parentGrid.Children.Add(grid);
            Grid.SetRow(grid, 0);
            var gnb = new GridnFloatingBtnCombo(grid,
                                                 AddToColumnStackPanel(layer)
                                               );
            if (columnLayerCnt > 0)
            {
                for (var i = layer.Level; i < columnLayerCnt; i++)
                {
                    gnb.ColumnDefinitions.Add(new ColumnDefinition
                    {
                        SharedSizeGroup = ColumnStr + (i + 1) + layer.ColumnLocation,
                        Width = GridLength.Auto
                    });
                    gnb.ColumnLocations.Add(layer.ColumnLocation);
                }
            }
            _columnLayers.Add(gnb);

        }

        private void SetupRowLayers(Grid parentGrid, Layer layer, int numberofRows)
        {
            var grid = new Grid
            {
                Name = RowStr + LayerStr + layer.Level,
                Visibility = Visibility.Collapsed
            };

            grid.RowDefinitions.Add(new RowDefinition
            {
                Height = new GridLength(1, GridUnitType.Star)
            });
            grid.RowDefinitions.Add(new RowDefinition
            {
                SharedSizeGroup = RowStr + layer.Level,
                Height = GridLength.Auto
            });
            //set up dock panel
            var dockpanel = new DockPanel
            {
                Margin = new Thickness(0, 4, 0, 0),
                Background = (RadialGradientBrush)PART_MasterGrid.FindResource("myColorfulLabelBrush"),
                LastChildFill = true
            };
            grid.Children.Add(dockpanel);
            Grid.SetRow(dockpanel, 1);
            var gridsplitter = new GridSplitter
            {
                Height = 4,
                Background = Brushes.CadetBlue,
                ResizeDirection = GridResizeDirection.Rows,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Top
            };
            grid.Children.Add(gridsplitter);
            Grid.SetRow(gridsplitter, 1);
            //set up stackpanel
            var stackpanel = new StackPanel
            {
                Height = 25.0,
                HorizontalAlignment = HorizontalAlignment.Stretch
            };
            dockpanel.Children.Add(stackpanel);
            DockPanel.SetDock(stackpanel, Dock.Top);
            //set up btn
            var btn = new Button
            {
                Name = RowStr + PinStr + layer.Level,
                Width = 26.0,
                HorizontalAlignment = HorizontalAlignment.Right,
                Background = Brushes.Transparent,
                BorderBrush = Brushes.Transparent,
                Style = (Style)PART_MasterGrid.FindResource("buttonStyle"),
                BorderThickness = new Thickness(0)
            };
            stackpanel.Children.Add(btn);
            var path = new Path
            {
                Stroke = Brushes.Black,
                Fill = Brushes.Gold,
                StrokeThickness = 1,
                Stretch = Stretch.Fill,
                Width = 9.0,
                Height = 15
            };
            var pathgeometry = PinPathgeometry();
            path.Data = pathgeometry;
            btn.Content = path;
            btn.Click += (o, e) =>
            {
                int level = layer.Level;
                var pgrid = parentGrid;
                var item = _rowLayers[level].Btn;
                if (item.Visibility == Visibility.Collapsed)
                    RowUndockPane(level, o as Button, pgrid);
                else
                    RowDockPane(level, o as Button, pgrid);
            };

            if (layer.Content != null)
            {
                dockpanel.Children.Add(layer.Content);
                DockPanel.SetDock(layer.Content, Dock.Top);
            }


            grid.MouseEnter += (o, e) =>
            {
                var level = layer.Level;
                for (var i = 1; i < _rowLayers.Count; i++)
                {
                    if (i == level)
                        continue;
                    if (_rowLayers[i].Btn.Visibility == Visibility.Visible)
                    {
                        _rowLayers[i].Grid.Visibility = Visibility.Collapsed;
                    }
                }
            };
            PART_MasterGrid.Children.Add(grid);
            Grid.SetRow(grid, 0);
            var gnb = new GridnFloatingBtnCombo(grid, AddToRowStackPanel(layer));
            if (numberofRows > 0)
            {
                for (int i = layer.Level; i < numberofRows; i++)
                {
                    gnb.RowDefinitions.Add(new RowDefinition
                    {
                        SharedSizeGroup = RowStr + (i + 1),
                        Height = GridLength.Auto
                    });
                }
            }
            _rowLayers.Add(gnb);
        }

        private static PathGeometry PinPathgeometry()
        {
            return new PathGeometry
            {
                Figures = new PathFigureCollection
                        {
                            new PathFigure
                                {
                                    StartPoint = new Point(10,0),
                                    
                                    IsFilled = true,
                                    
                                    Segments = new PathSegmentCollection
                                        {
                                            new LineSegment{Point = new Point(10,0)},
                                            new LineSegment{Point = new Point(30,0)},
                                            new LineSegment{Point = new Point(30,5)},
                                            new LineSegment{Point = new Point(10,5)},
                                            new LineSegment{Point = new Point(10,0)}
                                        }
                                },
                            new PathFigure
                                {
                                    StartPoint = new Point(4.5,5),
                                    Segments = new PathSegmentCollection
                                        {
                                            new LineSegment{Point = new Point(40.5,5)}
                                        }
                                },
                            new PathFigure
                                {
                                    StartPoint = new Point(22,5),
                                    Segments = new PathSegmentCollection
                                        {
                                            new LineSegment{Point = new Point(22,10)}
                                        }    
                                }
                        }
            };
        }

        private Button AddToRowStackPanel(Layer layer)
        {
            var btn = new Button
            {
                Background = Brushes.Transparent,
                BorderBrush = Brushes.Transparent,
                BorderThickness = new Thickness(0),
                Height = 24,
                Padding = new Thickness(10, 0, 15, 0),
                FontWeight = FontWeights.Bold,
                Style = (Style)PART_MasterGrid.FindResource("buttonStyle"),
                Content = layer.Name
            };
            btn.Click += (o, e) =>
            {
                var level = layer.Level;
                var item = _rowLayers[level];
                item.Grid.Visibility = Visibility.Visible;
                Grid.SetZIndex(item.Grid, 1);
                for (int i = 1; i < _rowLayers.Count; i++)
                {
                    if (i == level)
                        continue;
                    var loc = _rowLayers[i];
                    Grid.SetZIndex(loc.Grid, 0);
                    if (loc.Btn.Visibility == Visibility.Visible)
                        loc.Grid.Visibility = Visibility.Collapsed;

                }

            };
            PART_BottomCntl.Children.Add(btn);
            return btn;
        }

        private Button AddToColumnStackPanel(Layer layer)
        {
            var btn = new Button
            {
                Background = Brushes.Transparent,
                BorderBrush = Brushes.Transparent,
                BorderThickness = new Thickness(0),
                Height = 22,
                MinWidth = 65.0,
                Padding = new Thickness(10, 0, 15, 0),
                FontWeight = FontWeights.Bold,
                Style = (Style)PART_MasterGrid.FindResource("buttonStyle"),
                Content = layer.Name
            };
            btn.Click += (o, e) =>
            {
                var level = layer.Level;
                var item = _columnLayers[level];
                item.Grid.Visibility = Visibility.Visible;
                Grid.SetZIndex(item.Grid, 1);
                for (int i = 1; i < _columnLayers.Count; i++)
                {
                    if (i == level)
                        continue;
                    var loc = _columnLayers[i];
                    Grid.SetZIndex(loc.Grid, 0);
                    if (loc.Btn.Visibility == Visibility.Visible)
                        loc.Grid.Visibility = Visibility.Collapsed;

                }

            };
            if (layer.ColumnLocation == Layer.LayerColumnLocation.Right)
                PART_RightCntl.Children.Add(btn);
            else
                PART_LeftCntl.Children.Add(btn);
            return btn;
        }

        private void RowDockPane(int level, Button btn, Grid parentGrid)
        {
            var item = _rowLayers[level];
            item.Btn.Visibility = Visibility.Collapsed;
            var rtTrans = new RotateTransform(90);
            btn.LayoutTransform = rtTrans;
            parentGrid.RowDefinitions.Add(_rowLayers[0].RowDefinitions[level - 1]);
            for (var i = level + 1; i < _rowLayers.Count; i++)
            {
                if (_rowLayers[i].Btn.Visibility == Visibility.Collapsed)
                    item.Grid.RowDefinitions.Add(item.RowDefinitions[i - level - 1]);
            }
            for (var i = 1; i < level; i++)
            {
                var loc = _rowLayers[i];
                if (loc.Btn.Visibility == Visibility.Collapsed)
                    loc.Grid.RowDefinitions.Add(loc.RowDefinitions[level - 1 - i]);
            }
        }

        private void RowUndockPane(int level, Button btn, Grid parentGrid)
        {
            var item = _rowLayers[level];
            item.Btn.Visibility = Visibility.Visible;
            btn.LayoutTransform = null;
            item.Grid.Visibility = Visibility.Visible;
            parentGrid.RowDefinitions.Remove(_rowLayers[0].RowDefinitions[level - 1]);
            for (int i = 1; i < level; i++)
            {
                _rowLayers[i].Grid.RowDefinitions.Remove(_rowLayers[i].RowDefinitions[level - 1 - i]);
            }
            foreach (RowDefinition t in item.RowDefinitions)
            {
                item.Grid.RowDefinitions.Remove(t);
            }
        }

        private void ColumnDockPane(int level, Button btn)
        {
            var item = _columnLayers[level];
            item.Btn.Visibility = Visibility.Collapsed;
            var rtTrans = new RotateTransform(90);
            btn.LayoutTransform = rtTrans;
            if (_columnLayers[0].ColumnLocations[level - 1] == Layer.LayerColumnLocation.Right)
                _columnLayers[0].Grid.ColumnDefinitions.Add(_columnLayers[0].ColumnDefinitions[level - 1]);
            else
            {
                _columnLayers[0].MainContentPositionIncrement();
                _columnLayers[0].Grid.ColumnDefinitions.Insert(0, _columnLayers[0].ColumnDefinitions[level - 1]);
                Grid.SetColumn(_columnLayers[0].Grid.Children[0], _columnLayers[0].MainContentLocation);
            }

            for (var i = level + 1; i < _columnLayers.Count; i++)
            {
                if (_columnLayers[i].Btn.Visibility != Visibility.Collapsed)
                    continue;
                if (item.ColumnLocations[i - level - 1] == Layer.LayerColumnLocation.Right)
                    item.Grid.ColumnDefinitions.Add(item.ColumnDefinitions[i - level - 1]);
                else
                {
                    item.MainContentPositionIncrement();
                    item.Grid.ColumnDefinitions.Insert(0, item.ColumnDefinitions[i - level - 1]);
                    foreach (UIElement child in item.Grid.Children)
                    {
                        Grid.SetColumn(child, item.MainContentLocation - 1);
                    }
                }
            }
            for (var i = 1; i < level; i++)
            {
                var loc = _columnLayers[i];
                if (loc.Btn.Visibility != Visibility.Collapsed)
                    continue;
                if (loc.ColumnLocations[level - 1 - i] == Layer.LayerColumnLocation.Right)
                    loc.Grid.ColumnDefinitions.Add(loc.ColumnDefinitions[level - 1 - i]);
                else
                {
                    loc.MainContentPositionIncrement();
                    loc.Grid.ColumnDefinitions.Insert(0, loc.ColumnDefinitions[level - 1 - i]);
                    foreach (UIElement child in loc.Grid.Children)
                    {
                        Grid.SetColumn(child, loc.MainContentLocation - 1);
                    }

                }
            }
        }

        private void ColumnUndockPane(int level, Button btn)
        {
            var item = _columnLayers[level];
            item.Btn.Visibility = Visibility.Visible;
            btn.LayoutTransform = null;
            item.Grid.Visibility = Visibility.Visible;

            for (var i = 0; i < level; i++)
            {

                if (_columnLayers[i].ColumnLocations[level - 1 - i] == Layer.LayerColumnLocation.Left)
                {

                    _columnLayers[i].MainContentPositionDecrement();
                    if (i == 0)
                        Grid.SetColumn(_columnLayers[i].Grid.Children[0], _columnLayers[i].MainContentLocation);
                    else
                    {
                        foreach (UIElement child in _columnLayers[i].Grid.Children)
                        {
                            Grid.SetColumn(child, _columnLayers[i].MainContentLocation - 1);
                        }

                    }
                }
                _columnLayers[i].Grid.ColumnDefinitions.Remove(_columnLayers[i].ColumnDefinitions[level - 1 - i]);
            }
            int v = 0;
            foreach (var t in item.ColumnDefinitions)
            {

                if (item.ColumnLocations[v++] == Layer.LayerColumnLocation.Left)
                {
                    item.MainContentPositionDecrement();
                    foreach (UIElement child in item.Grid.Children)
                    {
                        Grid.SetColumn(child, item.MainContentLocation - 1);
                    }
                }
                item.Grid.ColumnDefinitions.Remove(t);
            }
        }


        #endregion
    }



    public class Layer : UIElement
    {
        public enum LayerOrientation
        {
            Row,
            Column
        }

        public enum LayerColumnLocation
        {
            Left,
            Right
        }
        public static readonly DependencyProperty LevelProperty;
        public static readonly DependencyProperty ContentProperty;
        public static readonly DependencyProperty OrientationProperty;
        public static readonly DependencyProperty NameProperty;
        public static readonly DependencyProperty ColumnLocationProperty;

        public int Level
        {
            get { return (int)GetValue(LevelProperty); }
            set { SetValue(LevelProperty, value); }
        }

        public UIElement Content
        {
            get { return (UIElement)GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }

        public LayerOrientation Orientation
        {
            get { return (LayerOrientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        public LayerColumnLocation ColumnLocation
        {
            get { return (LayerColumnLocation)GetValue(ColumnLocationProperty); }
            set { SetValue(ColumnLocationProperty, value); }
        }

        public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }

        static Layer()
        {
            LevelProperty = DependencyProperty.Register(
                                                "Level",
                                                typeof(int),
                                                typeof(Layer)
                                                );
            ContentProperty = DependencyProperty.Register(
                                                 "Content",
                                                 typeof(UIElement),
                                                 typeof(Layer)
                                                 );
            OrientationProperty = DependencyProperty.Register(
                                                    "Orientation",
                                                    typeof(LayerOrientation),
                                                    typeof(Layer));
            NameProperty = DependencyProperty.Register(
                                                    "Name",
                                                    typeof(string),
                                                    typeof(Layer));
            ColumnLocationProperty = DependencyProperty.Register(
                                                        "ColumnLocation",
                                                        typeof(LayerColumnLocation),
                                                        typeof(Layer),
                                                        new PropertyMetadata(LayerColumnLocation.Left)
                                                        );
        }

    }


}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions