ArcObjects Library Reference  

DockableDigit

About the Implementing a schematic digitizing tool Sample

[C#]

DockableDigit.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Xml;
using ESRI.ArcGIS.Schematic;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;

namespace DigitTool
{
    /// <summary>
    /// Designer class of the dockable window add-in. It contains user interfaces that
    /// make up the dockable window.
    /// </summary>
    public partial class DigitDockableWindow : UserControl
    {
        private DigitTool m_digitCommand;

        private XmlDocument m_dom = null;
        private bool m_loading = true;
        private bool m_clickPanel = false;
        private long m_curfrmWidth;

        private System.Windows.Forms.SplitterPanel m_Panel1;
        private System.Windows.Forms.SplitterPanel m_Panel2;

        private System.Windows.Forms.SplitterPanel m_curPanel;
        private System.Drawing.Color m_MandatoryColor = System.Drawing.Color.White;

        private ISchematicLayer m_schematicLayer;
        private ISchematicFeature m_schematicFeature1 = null;
        private ISchematicFeature m_schematicFeature2 = null;
        private bool m_createNode = true; //update when click on panel and on new
        private bool m_isClosed = false;
        private ESRI.ArcGIS.Framework.IApplication m_app;

        //For button OK to retrieve the coordinate of the digit feature
        private int m_x;
        private int m_y;

        private XmlElement m_curLink = null;
        private XmlElement m_curNode = null;
        private XmlNodeList m_relations = null;
        private ISchematicDataset m_schDataset = null;
        private ISchematicElementClassContainer m_schEltClassCont = null;
        private ISchematicElementClass m_schEltClass = null;
        private ISchematicInMemoryDiagram m_SchematicInMemoryDiagram = null;
        private bool m_autoClear = false;


        public DigitDockableWindow(object hook)
        {
            InitializeComponent();
            this.Hook = hook;
        }

        /// <summary>
        /// Host object of the dockable window
        /// </summary>
        private object Hook
        {
            get;
            set;
        }

        /// <summary>
        /// Implementation class of the dockable window add-in. It is responsible for 
        /// creating and disposing the user interface class of the dockable window.
        /// </summary>
        public class AddinImpl : ESRI.ArcGIS.Desktop.AddIns.DockableWindow
        {
            private DigitDockableWindow m_windowUI;

            public AddinImpl()
            {
            }

            protected override IntPtr OnCreateChild()
            {
                m_windowUI = new DigitDockableWindow(this.Hook);

                CurrentDigitTool.CurrentTool.digitDockableWindow = m_windowUI;

                if (CurrentDigitTool.CurrentTool.currentDigit != null)
                {
                    m_windowUI.m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;
                    m_windowUI.m_digitCommand.m_dockableDigit = m_windowUI;
                }
                else
                {
                    // CurrentDigitTool.CurrentTool.CurrentDigit is null when we open ArcMap, but OnCreateChild
                    // is called if the dockable window was shown during the last ArcMap session.
                    ESRI.ArcGIS.Framework.IDockableWindowManager dockWinMgr = ArcMap.DockableWindowManager;
                    UID u= new UID();
                    u.Value = "DigitTool_DockableWindowCS";
                    CurrentDigitTool.CurrentTool.currentDockableWindow = dockWinMgr.GetDockableWindow(u);
                }

                return m_windowUI.Handle;
            }

            protected override void Dispose(bool disposing)
            {
                if (m_windowUI != null)
                    m_windowUI.Dispose(disposing);

                base.Dispose(disposing);
            }

        }

        public void Init(ISchematicLayer schematicLayer)
        {
            try
            {
                if (schematicLayer == null)
                    return;

                m_schematicLayer = schematicLayer;
                XmlNode col = null;
                String myString = "";

                m_schDataset = schematicLayer.SchematicDiagram.SchematicDiagramClass.SchematicDataset;

                m_schEltClassCont = (ISchematicElementClassContainer)m_schDataset;
                m_SchematicInMemoryDiagram = schematicLayer.SchematicInMemoryDiagram;

                m_dom = new XmlDocument();

                ISchematicDiagram schematicDiagram;
                schematicDiagram = m_SchematicInMemoryDiagram.SchematicDiagram;

                // get the path of the xml file that contains the definitions of the digitize dockable window
                String path;

                ISchematicDiagramClass schematicDiagramClass = schematicDiagram.SchematicDiagramClass;
                ISchematicAttributeContainer schematicAttributeContainer = (ISchematicAttributeContainer)schematicDiagramClass;

                ISchematicAttribute schematicAttribute = schematicAttributeContainer.GetSchematicAttribute("DigitizePropertiesLocation", true);

                if (schematicAttribute == null)
                {
                    System.Windows.Forms.MessageBox.Show("Need an attribute named DigitizePropertiesLocation in the corresponding DiagramTemplate attributes");
                    return;
                }

                path = (string)schematicAttribute.GetValue((ISchematicObject)schematicDiagram);

                if (IsRelative(path)) //Concat the workspace's path with this path
                {
                    //current workspace path
                    ISchematicDataset myDataset = schematicDiagramClass.SchematicDataset;
                    if (myDataset != null)
                    {
                        ISchematicWorkspace mySchematicWorkspace = myDataset.SchematicWorkspace;
                        if (mySchematicWorkspace != null)
                        {
                            ESRI.ArcGIS.Geodatabase.IWorkspace myWorkspace = mySchematicWorkspace.Workspace;
                            if (myWorkspace != null)
                            {
                                string workspacePath = myWorkspace.PathName;
                                //add "..\" to path to step back one level...
                                string stepBack = "..\\";
                                path = stepBack + path;

                                path = System.IO.Path.Combine(workspacePath, path);
                            }
                        }
                    }
                }
                //else keep the original hard path

                XmlReader reader = XmlReader.Create(path);

                m_dom.Load(reader);

                //Load Nodes
                XmlNodeList nodes = m_dom.SelectNodes("descendant::NodeFeature");

                //Clear combo box after each call
                cboNodeType.Items.Clear();
                foreach (XmlElement node in nodes)
                {
                    cboNodeType.Items.Add(node.GetAttribute("FeatureClassName").ToString());
                }


                //Load Links
                XmlNodeList links = m_dom.SelectNodes("descendant::LinkFeature");

                //Clear combo box after each call
                cboLinkType.Items.Clear();
                foreach (XmlElement link in links)
                {
                    cboLinkType.Items.Add(link.GetAttribute("FeatureClassName").ToString());
                }

                col = m_dom.SelectSingleNode("descendant::MandatoryColor");
                if (col != null)
                {
                    myString = "System.Drawing.";
                    myString = col.InnerText.ToString();
                    m_MandatoryColor = System.Drawing.Color.FromName(myString);
                }

                col = m_dom.SelectSingleNode("descendant::FormName");
                if (col != null)
                {
                    myString = col.InnerText.ToString();
                    Text = myString;
                }


                XmlNodeList rels = m_dom.SelectNodes("descendant::Relation");
                if (rels.Count > 0)
                    m_relations = rels;

                col = m_dom.SelectSingleNode("descendant::AutoClearAfterCreate");
                if ((col != null) && col.InnerText.ToString() == "True")
                    m_autoClear = true;

            }
            catch (System.Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
            }

            m_Panel1 = Splitter.Panel1;
            m_Panel2 = Splitter.Panel2;
            m_curPanel = Splitter.Panel1;
            lblMode.Text = "Create Node";
            m_loading = false;
            m_clickPanel = false;
            m_schEltClass = null;

        }

        public bool ValidateFields()
        {
            bool blnValidated = true;
            System.Windows.Forms.MaskedTextBox mctrl = null;
            string errors = "";

            //check all mandatory fields
            System.Windows.Forms.Control ctrl2;

            foreach (System.Windows.Forms.Control ctrl in m_curPanel.Controls)
            {
                ctrl2 = ctrl;
                if (ctrl2.GetType() == typeof(System.Windows.Forms.Label))
                {
                }
                //ignore labels
                else
                {
                    if ((string)ctrl2.Tag == "Mandatory")
                    {
                        if (ctrl2.GetType() == typeof(System.Windows.Forms.MaskedTextBox))
                        {
                            mctrl = (System.Windows.Forms.MaskedTextBox)ctrl2;
                            if (mctrl.MaskCompleted == false)
                            {
                                blnValidated = false;
                                if (errors.Length > 0)
                                    errors = "Incomplete mandatory field";
                                else
                                    errors = errors + "\n" + "Incomplete mandatory field";
                            }
                        }
                        else
                        {
                            if (ctrl2.Text.Length <= 0)
                            {
                                blnValidated = false;
                                if (errors.Length <= 0)
                                    errors = "Incomplete mandatory field";
                                else
                                    errors = errors + "\n" + "Incomplete mandatory field";
                            }
                        }
                    }


                    //check masked edit controls
                    if (ctrl2.GetType() == typeof(System.Windows.Forms.MaskedTextBox))
                    {
                        mctrl = (System.Windows.Forms.MaskedTextBox)ctrl2;
                        //if they typed something, but didn't complete it, then error
                        //if they typed nothing and it is not mandatory, then it is OK
                        if ((mctrl.Text.Length > 0) && mctrl.Modified && (!mctrl.MaskCompleted))
                        {
                            blnValidated = false;
                            if (errors.Length > 0)
                                errors = "Invalid entry in a masked text field";
                            else
                                errors = errors + "\n" + "Invalid entry in a masked text field";
                        }
                    }

                    //check link connections
                    if (m_curPanel == Splitter.Panel2)
                    {
                        //make sure that the relation is correct if it exists
                        XmlNodeList fields = m_curLink.SelectNodes("descendant::Field");
                        foreach (XmlElement field in fields)
                        {
                            //find the field with a type of "Relation"
                            if (field.GetAttribute("Type") == "Relation")
                            {
                                ESRI.ArcGIS.Geodatabase.IDataset pDataset1;
                                ESRI.ArcGIS.Geodatabase.IDataset pDataset2;

                                string FeatureClass1Name;
                                string FeatureClass2Name;

                                pDataset1 = (ESRI.ArcGIS.Geodatabase.IDataset)m_schematicFeature1.SchematicElementClass;
                                pDataset2 = (ESRI.ArcGIS.Geodatabase.IDataset)m_schematicFeature2.SchematicElementClass;

                                FeatureClass1Name = pDataset1.Name;
                                FeatureClass2Name = pDataset2.Name;

                                foreach (XmlElement rel in m_relations)
                                {
                                    //loop through the xml relations to match based on the from node and to node types

                                    if ((rel.GetAttribute("FromType") == FeatureClass1Name) && (rel.GetAttribute("ToType") == FeatureClass2Name))
                                    {
                                        //find the control with the pick list for relationships
                                        Control[] ctrls = m_curPanel.Controls.Find(field.GetAttribute("DBColumnName"), true);
                                        if (ctrls.Length > 0)
                                            ctrl2 = ctrls[0];

                                        XmlNodeList vals = rel.SelectNodes("descendant::Value");
                                        string myString = rel.GetAttribute("FromType") + "-" + rel.GetAttribute("ToType");
                                        //validate that the current control string is correct
                                        //if there are values, use them
                                        bool blnfound = false;
                                        if (vals.Count > 0)
                                        {
                                            foreach (XmlElement val in vals)
                                            {
                                                if (myString + "-" + val.InnerText.ToString() == ctrl2.Text)
                                                {
                                                    blnfound = true;
                                                    break;
                                                }
                                                else
                                                    blnfound = false;
                                            }
                                            if (!blnfound)
                                            {
                                                blnValidated = false;
                                                if (errors.Length > 0)
                                                    errors = "Invalid link connection";
                                                else
                                                    errors = errors + "\n" + "Invalid link connection";
                                            }
                                        }
                                        else
                                        {
                                            if (ctrl2.Text != myString)
                                            {
                                                blnValidated = false;
                                                if (errors.Length > 0)
                                                    errors = "Invalid link connection";
                                                else
                                                    errors = errors + "\n" + "Invalid link connection";
                                            }
                                        }

                                        if (!blnfound) //fix connection list
                                        {
                                            XmlNodeList vlist = m_dom.SelectNodes("descendant::Relation");
                                            XmlNodeList rellist = null;
                                            System.Windows.Forms.ComboBox cboconn = (System.Windows.Forms.ComboBox)ctrl2;
                                            cboconn.Items.Clear();
                                            foreach (XmlElement v in vlist)
                                            {
                                                if ((v.GetAttribute("LinkType").ToString() == m_curLink.GetAttribute("FeatureClassName").ToString())
                                                    //make sure the node types are ok
                                                    && ((v.GetAttribute("FromType").ToString() == FeatureClass1Name && (v.GetAttribute("ToType").ToString() == FeatureClass2Name))))
                                                {
                                                    rellist = v.SelectNodes("descendant::Value");
                                                    if (rellist.Count > 0)
                                                    {
                                                        foreach (XmlElement r in rellist)
                                                        {
                                                            myString = v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString() + "-" + r.InnerText.ToString();
                                                            cboconn.Items.Add(myString);
                                                        }
                                                    }
                                                    else //assume they are not using subtypes
                                                        cboconn.Items.Add(v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString());
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (errors.Length > 0)
            {

                if (m_curPanel == Splitter.Panel1)
                {
                    btnOKPanel1.Visible = true;
                    ErrorProvider1.SetError(btnOKPanel1, errors);
                }
                else
                {
                    btnOKPanel2.Visible = true;
                    ErrorProvider1.SetError(btnOKPanel2, errors);
                }
            }
            return blnValidated;

        }

        public void SelectionChanged()
        {

            try
            {
                System.Windows.Forms.Control ctrl = null;
                System.Windows.Forms.Control ctrl2 = null;
                Control[] ctrls = null;
                System.Collections.ArrayList ctrlstoremove = new System.Collections.ArrayList();
                string labelName = "";
                string featureClass = "";
                System.Windows.Forms.ComboBox cbo = null;
                System.Windows.Forms.Label lblMain = null;

                if (m_digitCommand == null)
                    return;

                //clear any current elements
                if (m_schematicFeature1 != null)
                {
                    m_schematicFeature1 = null;
                    m_digitCommand.SchematicFeature1(m_schematicFeature1);
                }

                if (m_schematicFeature2 != null)
                {
                    m_schematicFeature2 = null;
                    m_digitCommand.SchematicFeature2(m_schematicFeature2);
                }

                if (m_curPanel == Splitter.Panel1)
                {
                    labelName = "lblNodeLabel";
                    featureClass = "descendant::NodeFeature";
                    cbo = cboNodeType;
                    lblMain = lblNodeLabel;
                }
                else
                {
                    labelName = "lblLinkLabel";
                    featureClass = "descendant::LinkFeature";
                    cbo = cboLinkType;
                    lblMain = lblLinkLabel;
                }

                foreach (System.Windows.Forms.Control ctrlfor in m_curPanel.Controls)
                {
                    if (ctrlfor.Name.StartsWith("lbl") && (ctrlfor.Name.ToString() != labelName))
                    {
                        ctrls = m_curPanel.Controls.Find(ctrlfor.Name.Substring(3), true);
                        ctrl2 = ctrls[0];
                        ctrlstoremove.Add(ctrlfor);
                        ctrlstoremove.Add(ctrl2);
                    }
                }

                if (ctrlstoremove.Count > 0)
                {
                    foreach (System.Windows.Forms.Control ctrol in ctrlstoremove)
                    {
                        m_curPanel.Controls.Remove(ctrol);
                    }
                }

                XmlNodeList elems = null;
                m_curfrmWidth = m_curPanel.Width;
                elems = m_dom.SelectNodes(featureClass);

                bool blnFound = false;
                XmlElement elem = null;
                foreach (XmlElement elem0 in elems)
                {
                    if (elem0.GetAttribute("FeatureClassName").ToString() == cbo.Text.ToString())
                    {
                        elem = elem0;
                        blnFound = true;
                        break;
                    }
                }

                if (blnFound == false)
                {
                    m_schEltClass = null;
                    return;
                }

                if (m_curPanel == Splitter.Panel1)
                    m_curNode = elem;
                else
                    m_curLink = elem;

                //set grid
                elems = elem.SelectNodes("descendant::Field");
                int x = Splitter.Location.X;
                int y = lblMain.Location.Y + lblMain.Height + 5;

                System.Drawing.Point p = new System.Drawing.Point();

                foreach (XmlElement f in elems)
                {
                    System.Windows.Forms.Label lbl = new System.Windows.Forms.Label();
                    lbl.Name = "lbl" + f.GetAttribute("DBColumnName").ToString();
                    lbl.Text = f.GetAttribute("DisplayName").ToString();
                    lbl.AutoSize = true;
                    m_curPanel.Controls.Add(lbl);
                    p.X = 3;
                    p.Y = y;
                    lbl.Location = p;
                    y = y + lbl.Height + 10;

                    switch (f.GetAttribute("Type").ToString())
                    {
                        case "Text":
                            System.Windows.Forms.TextBox tx = new System.Windows.Forms.TextBox();
                            ctrl = tx;
                            tx.Name = f.GetAttribute("DBColumnName").ToString();
                            if (f.GetAttribute("Length").Length > 0)
                                tx.MaxLength = System.Convert.ToInt32(f.GetAttribute("Length"));

                            if (f.GetAttribute("Default").Length > 0)
                                tx.Text = f.GetAttribute("Default");

                            m_curPanel.Controls.Add(tx);
                            break;

                        case "Combo":

                            System.Windows.Forms.ComboBox cb = new System.Windows.Forms.ComboBox();
                            string defaulttext = "";
                            ctrl = cb;
                            cb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
                            cb.Name = f.GetAttribute("DBColumnName").ToString();
                            XmlNodeList vlist = f.SelectNodes("descendant::Value");

                            foreach (XmlElement v in vlist)
                            {
                                cb.Items.Add(v.InnerText.ToString());
                                if (v.GetAttribute("Default").Length > 0)
                                    defaulttext = v.InnerText;
                            }

                            if (defaulttext.Length > 0)
                                cb.Text = defaulttext;

                            m_curPanel.Controls.Add(cb);
                            break;

                        case "MaskText":
                            System.Windows.Forms.MaskedTextBox MaskControl = new System.Windows.Forms.MaskedTextBox();
                            ctrl = MaskControl;
                            string mask = "";
                            MaskControl.Name = f.GetAttribute("DBColumnName").ToString();
                            if (f.GetAttribute("Mask").Length > 0)
                                mask = f.GetAttribute("Mask");
                            else
                                mask = "";

                            MaskControl.Mask = mask;

                            if (f.GetAttribute("Default").Length > 0)
                                MaskControl.Text = f.GetAttribute("Default");

                            MaskControl.Modified = false;
                            m_curPanel.Controls.Add(MaskControl);
                            MaskControl.TextChanged += new System.EventHandler(MaskedTextBox);

                            break;

                        case "Number":
                            System.Windows.Forms.MaskedTextBox MaskControl2 = new System.Windows.Forms.MaskedTextBox();
                            ctrl = MaskControl2;
                            string mask2 = "";
                            MaskControl2.Name = f.GetAttribute("DBColumnName").ToString();
                            int i = 1;
                            if (f.GetAttribute("Length").Length > 0)
                            {
                                for (i = 1; i <= System.Convert.ToInt32(f.GetAttribute("Length")); i++)
                                    mask = mask2 + "9";
                            }
                            else
                            {
                                if (f.GetAttribute("Mask").Length > 0)
                                    mask2 = f.GetAttribute("Mask");
                                else
                                    mask2 = "";
                            }

                            MaskControl2.Mask = mask2;
                            if (f.GetAttribute("Default").Length > 0)
                                MaskControl2.Text = f.GetAttribute("Default");

                            MaskControl2.Modified = false;
                            m_curPanel.Controls.Add(MaskControl2);
                            MaskControl2.TextChanged += new System.EventHandler(MaskedTextBox);
                            break;

                        case "Date":
                            System.Windows.Forms.DateTimePicker dt = new System.Windows.Forms.DateTimePicker();
                            ctrl = dt;
                            dt.Name = f.GetAttribute("DBColumnName").ToString();
                            dt.Value = DateTime.Now;
                            dt.Format = System.Windows.Forms.DateTimePickerFormat.Short;
                            m_curPanel.Controls.Add(dt);
                            break;

                        case "Relation":
                            System.Windows.Forms.ComboBox cb2 = new System.Windows.Forms.ComboBox();
                            ctrl = cb2;
                            cb2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
                            cb2.Name = f.GetAttribute("DBColumnName").ToString();
                            XmlNodeList vlist2 = m_dom.SelectNodes("descendant::Relation");
                            XmlNodeList rellist = null;
                            string str = null;
                            foreach (XmlElement v in vlist2)
                            {
                                if (v.GetAttribute("LinkType").ToString() == elem.GetAttribute("FeatureClassName").ToString())
                                {
                                    rellist = v.SelectNodes("descendant::Value");
                                    if (rellist.Count > 0)
                                        foreach (XmlElement r in rellist)
                                        {
                                            str = v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString() + "-" + r.InnerText.ToString();
                                            cb2.Items.Add(str);
                                        }
                                    else //assume they are not using subtypes
                                        cb2.Items.Add(v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString());
                                }
                            }
                            //relations are always mandatory
                            ctrl.BackColor = m_MandatoryColor;
                            ctrl.Tag = "Mandatory";
                            m_curPanel.Controls.Add(cb2);
                            break;
                    }

                    if (f.GetAttribute("Mandatory").ToString() == "True")
                    {
                        ctrl.BackColor = m_MandatoryColor;
                        ctrl.Tag = "Mandatory";
                    }
                }
                ResizeForm();

                // set m_schEltClass
                XmlElement curElement = null;

                if (m_curPanel == Splitter.Panel1)
                    curElement = m_curNode;
                else
                    curElement = m_curLink;

                if (m_schEltClass == null)
                    m_schEltClass = m_schEltClassCont.GetSchematicElementClass(curElement.GetAttribute("FeatureClassName"));
                else
                    if (m_schEltClass.Name != curElement.GetAttribute("FeatureClassName"))
                        m_schEltClass = m_schEltClassCont.GetSchematicElementClass(curElement.GetAttribute("FeatureClassName"));
            }

            catch (System.Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
            }
        }

        public bool CheckValidFeature(bool blnFromNode)
        {
            if (m_curLink == null)
                return false;

            XmlNodeList fields = m_curLink.SelectNodes("descendant::Field");

            foreach (XmlElement field in fields)
            {
                if (field.GetAttribute("Type") == "Relation")
                {
                    foreach (XmlElement rel in m_relations)
                    {
                        if (blnFromNode)
                        {
                            if (m_schematicFeature1 == null)
                                return false;

                            if (rel.GetAttribute("FromType") == m_schematicFeature1.SchematicElementClass.Name)
                                return true;
                        }
                        else
                        {
                            if (m_schematicFeature2 == null)
                                return false;

                            if (rel.GetAttribute("ToType") == m_schematicFeature2.SchematicElementClass.Name)
                                return true;
                        }
                    }
                    return false;
                }
            }
            return true;
        }

        public void FillValue(ref ISchematicFeature schFeature)
        {
            try
            {
                if (m_schEltClass == null)
                    throw new Exception("Error getting Feature Class");

                int fldIndex;

                foreach (System.Windows.Forms.Control ctrl in m_curPanel.Controls)
                {
                    if (!((ctrl.GetType() == typeof(System.Windows.Forms.Label)) || (ctrl.Name == "cboNodeType")))
                    {
                        if ((ctrl.GetType() == typeof(System.Windows.Forms.TextBox)) || (ctrl.GetType() == typeof(System.Windows.Forms.ComboBox)))
                        {
                            if (ctrl.Text.Length > 0)
                            {
                                //insert in DB
                                fldIndex = schFeature.Fields.FindField(ctrl.Name);
                                if (fldIndex > -1)
                                {
                                    schFeature.set_Value(fldIndex, ctrl.Text);
                                    schFeature.Store();
                                }
                            }
                        }
                        else if (ctrl.GetType() == typeof(System.Windows.Forms.DateTimePicker))
                        {
                            fldIndex = schFeature.Fields.FindField(ctrl.Name);
                            if (fldIndex > -1)
                            {
                                schFeature.set_Value(fldIndex, ctrl.Text);
                                schFeature.Store();
                            }
                        }
                        else if (ctrl.GetType() == typeof(System.Windows.Forms.MaskedTextBox))
                        {
                            System.Windows.Forms.MaskedTextBox mctrl = (System.Windows.Forms.MaskedTextBox)ctrl;
                            if ((mctrl.Text.Length > 0) && (mctrl.Modified) && (mctrl.MaskCompleted))
                            {

                                fldIndex = schFeature.Fields.FindField(ctrl.Name);
                                if (fldIndex > -1)
                                {
                                    schFeature.set_Value(fldIndex, ctrl.Text);
                                    schFeature.Store();
                                }
                            }
                        }
                    }
                }

                return;
            }

            catch (System.Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
            }
        }

        private void ResizeForm()
        {
            try
            {
                System.Windows.Forms.Control ctr2;
                Control[] ctrls = null;
                System.Drawing.Point p = new System.Drawing.Point();
                //handle panel 1
                foreach (System.Windows.Forms.Control ctr in Splitter.Panel1.Controls)
                {
                    if ((ctr.Name.StartsWith("lbl")) && (ctr.Name.ToString() != "lblNodeLabel"))
                    {
                        ctrls = Splitter.Panel1.Controls.Find(ctr.Name.Substring(3), true);
                        if (ctrls.GetLength(0) > 0)
                        {
                            ctr2 = ctrls[0];

                            p.Y = ctr.Location.Y;
                            p.X = ctr.Width + 3;
                            ctr2.Location = p;
                            ctr2.Width = Splitter.Panel1.Width - ctr.Width - 5;
                        }
                    }
                }

                Splitter.Panel1.Refresh();
                //handle panel 2
                foreach (System.Windows.Forms.Control ctr in Splitter.Panel2.Controls)
                {
                    if ((ctr.Name.StartsWith("lbl")) && (ctr.Name.ToString() != "lblLinkLabel"))
                    {
                        ctrls = Splitter.Panel2.Controls.Find(ctr.Name.Substring(3), true);
                        if (ctrls.GetLength(0) > 0)
                        {
                            ctr2 = ctrls[0];
                            p.Y = ctr.Location.Y;
                            p.X = ctr.Width + 3;
                            ctr2.Location = p;
                            ctr2.Width = Splitter.Panel2.Width - ctr.Width - 5;
                        }
                    }
                }

                Splitter.Panel2.Refresh();
            }
            catch (System.Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
            }
        }

        private void cboType_SelectedIndexChanged(Object sender, System.EventArgs e)
        {
            SelectionChanged();
        }

        public void cboLinkType_SelectedIndexChanged(Object sender, System.EventArgs e)
        {
            SelectionChanged();
        }

        private void MaskedTextBox(Object sender, System.EventArgs e)
        {
            System.Windows.Forms.MaskedTextBox mctrl = (System.Windows.Forms.MaskedTextBox)sender;
            mctrl.Modified = true;
        }

        /// <summary>
        /// m_createNode is true when the active panel is the one that digitize nodes.
        /// </summary>
        /// <returns></returns>
        public bool CreateNode()
        {
            return m_createNode;
        }

        public bool AutoClear()
        {
            return m_autoClear;
        }

        public bool IsClosed()
        {
            return m_isClosed;
        }

        public ISchematicElementClass FeatureClass()
        {
            return m_schEltClass;
        }

        public void x(int x)
        {
            m_x = x;
            return;
        }

        public void y(int y)
        {
            m_y = y;
            return;
        }

        public void SchematicFeature1(ISchematicFeature schematicFeature)
        {
            m_schematicFeature1 = schematicFeature;
            return;
        }

        public void SchematicFeature2(ISchematicFeature schematicFeature)
        {
            m_schematicFeature2 = schematicFeature;
            return;
        }

        public void FrmApplication(ESRI.ArcGIS.Framework.IApplication app)
        {
            m_app = app;
            return;
        }

        private void Splitter_Panel2_Click(object sender, EventArgs e)
        {
            if (m_digitCommand == null)
                m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;

            if (m_digitCommand == null)
                return;
            
            m_createNode = false;

            if (m_curPanel != Splitter.Panel2)
            {

                m_curPanel = Splitter.Panel2;
                foreach (System.Windows.Forms.Control ctrl in Splitter.Panel1.Controls)
                    ctrl.Enabled = false;

                foreach (System.Windows.Forms.Control ctrl in Splitter.Panel2.Controls)
                    ctrl.Enabled = true;

                lblMode.Text = "Create Link";

                if (m_schematicFeature1 != null)
                {
                    m_schematicFeature1 = null;
                    m_digitCommand.SchematicFeature1(m_schematicFeature1);
                }

                if (m_schematicFeature2 != null)
                {
                    m_schematicFeature2 = null;
                    m_digitCommand.SchematicFeature2(m_schematicFeature2);
                }

                if (m_curPanel == Splitter.Panel1)
                {
                    btnOKPanel1.Visible = false;
                    ErrorProvider1.SetError(btnOKPanel1, "");
                }
                else
                {
                    btnOKPanel2.Visible = false;
                    ErrorProvider1.SetError(btnOKPanel2, "");
                }

                System.EventArgs e2 = new System.EventArgs();
                cboLinkType_SelectedIndexChanged(sender, e2);

            }

        }

        private void Splitter_Panel1_Click(object sender, EventArgs e)
        {
            if (m_digitCommand == null)
                m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;

            if (m_digitCommand != null)
                m_digitCommand.EndFeedBack();

            m_createNode = true;

            if (m_curPanel != Splitter.Panel1 || m_clickPanel == false)
            {
                m_clickPanel = true;
                m_curPanel = Splitter.Panel1;

                foreach (System.Windows.Forms.Control ctrl in Splitter.Panel2.Controls)
                    ctrl.Enabled = false;

                foreach (System.Windows.Forms.Control ctrl in Splitter.Panel1.Controls)
                    ctrl.Enabled = true;

                lblMode.Text = "Create Node";

                if (m_curPanel == Splitter.Panel1)
                {
                    btnOKPanel1.Visible = false;
                    ErrorProvider1.SetError(btnOKPanel1, "");
                }
                else
                {
                    btnOKPanel2.Visible = false;
                    ErrorProvider1.SetError(btnOKPanel2, "");
                }
                System.EventArgs e2 = new System.EventArgs();
                cboType_SelectedIndexChanged(sender, e2);
            }
        }

        private void btnOKPanel1_Click(object sender, EventArgs e)
        {
            //try to create the node at the original point
            if (m_digitCommand != null)
                m_digitCommand.MyMouseUp(m_x, m_y);

            ErrorProvider1.SetError(btnOKPanel1, "");
            btnOKPanel1.Visible = false;
        }

        private void btnOKPanel2_Click(object sender, EventArgs e)
        {
            //try to create the link with the original points
            if (m_digitCommand != null)
                m_digitCommand.MyMouseUp(m_x, m_y);

            ErrorProvider1.SetError(btnOKPanel1, "");
            btnOKPanel1.Visible = false;
        }

        private void WindowVisibleChange(object sender, EventArgs e)
        {

            if (m_digitCommand == null)
                m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;

            if (m_digitCommand == null)
                return;

            if ((this.Visible) && !CurrentDigitTool.CurrentTool.currentDockableWindow.IsVisible())
            {
                if (!(m_digitCommand.FromDeactivate()))
                {
                    m_digitCommand.DeactivatedFromDock(true);
                    
                    ESRI.ArcGIS.Framework.IApplication app = (ESRI.ArcGIS.Framework.IApplication)this.Hook;
                    app.CurrentTool = null;
                }
            }
            m_digitCommand.EndFeedBack();
            m_digitCommand.FromDeactivate(false);
        }
        
        private void DigitWindow_Resize(object sender, EventArgs e)
        {
            if (!m_loading)
                ResizeForm();
        }
         

        //IsRelative return true when the path start with "."
        private bool IsRelative(string path)
        {
            bool startwith = path.StartsWith(".");
            return startwith;
        }

    }
}

[Visual Basic .NET]

DockableDigit.vb

Imports System.Xml
Imports ESRI.ArcGIS.Schematic
Imports ESRI.ArcGIS.esriSystem

''' <summary>
''' Designer class of the dockable window add-in. It contains user interfaces that
''' make up the dockable window.
''' </summary>
Public Class DigitDockableWindow

    Private m_digitCommand As DigitTool

    Dim m_dom As XmlDocument = Nothing
    Dim m_loading As Boolean = True
    Dim m_clickPanel As Boolean = False
    Dim m_curfrmWidth As Long
    Friend WithEvents m_Panel1 As System.Windows.Forms.SplitterPanel
    Friend WithEvents m_Panel2 As System.Windows.Forms.SplitterPanel
    Dim m_curPanel As System.Windows.Forms.SplitterPanel
    Dim m_mandatoryColor As System.Drawing.Color = Drawing.Color.White

    Private m_schematicLayer As ISchematicLayer
    Private m_schematicFeature1 As ISchematicFeature = Nothing
    Private m_schematicFeature2 As ISchematicFeature = Nothing
    Private m_createNode As Boolean = True 'update when click on panel and on new

    'For button OK to retrieve the coordinate of the digit feature
    Private m_x As Integer
    Private m_y As Integer

    Private m_curLink As XmlElement = Nothing
    Private m_curNode As XmlElement = Nothing
    Private m_relations As XmlNodeList = Nothing
    Private m_schDataset As ISchematicDataset = Nothing
    Private m_schEltClassCont As ISchematicElementClassContainer = Nothing
    Private m_schEltClass As ISchematicElementClass = Nothing
    Private m_schematicInMemoryDiagram As ISchematicInMemoryDiagram = Nothing
    Private m_autoClear As Boolean = False
    Private m_schematicExtension As ESRI.ArcGIS.esriSystem.IExtension

    Public Sub New(ByVal hook As Object)

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Me.Hook = hook

    End Sub



    Private m_hook As Object
    ''' <summary>
    ''' Host object of the dockable window
    ''' </summary> 
    Public Property Hook() As Object
        Get
            Return m_hook
        End Get
        Set(ByVal value As Object)
            m_hook = value
        End Set
    End Property

    ''' <summary>
    ''' Implementation class of the dockable window add-in. It is responsible for
    ''' creating and disposing the user interface class for the dockable window.
    ''' </summary>
    Public Class AddinImpl
        Inherits ESRI.ArcGIS.Desktop.AddIns.DockableWindow

        Private m_windowUI As DigitDockableWindow

        Protected Overrides Function OnCreateChild() As System.IntPtr
            m_windowUI = New DigitDockableWindow(Me.Hook)

            CurrentDigitTool.CurrentTool.digitDockableWindow = m_windowUI

            If (CurrentDigitTool.CurrentTool.currentDigit IsNot Nothing) Then
                m_windowUI.m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit
                m_windowUI.m_digitCommand.m_dockableDigit = m_windowUI
            Else
                ' CurrentDigitTool.CurrentTool.CurrentDigit is null when we open ArcMap, but OnCreateChild
                ' is called if the dockable window was shown during the last ArcMap session.
                Dim windowID As UID = New UIDClass
                windowID.Value = "DigitTool_DockableWindowVB"
                CurrentDigitTool.CurrentTool.currentDockableWindow = My.ArcMap.DockableWindowManager.GetDockableWindow(windowID)
            End If

            Return m_windowUI.Handle
        End Function

        Protected Overrides Sub Dispose(ByVal Param As Boolean)
            If m_windowUI IsNot Nothing Then
                m_windowUI.Dispose(Param)
            End If

            MyBase.Dispose(Param)

        End Sub

    End Class


    Public Sub Init(ByVal schematicLayer As ISchematicLayer)

        Try

            If schematicLayer Is Nothing Then
                Return
            End If

            m_schematicLayer = schematicLayer
            Dim col As XmlNode = Nothing
            Dim myString As String = Nothing

            m_schDataset = schematicLayer.SchematicDiagram.SchematicDiagramClass.SchematicDataset

            m_schEltClassCont = m_schDataset
            m_schematicInMemoryDiagram = schematicLayer.SchematicInMemoryDiagram

            m_dom = New XmlDocument

            Dim schematicDiagram As ISchematicDiagram
            schematicDiagram = m_schematicInMemoryDiagram.SchematicDiagram

            ' get the path of the xml file that contains the definitions of the digitize dockable window
            Dim path As String

            Dim schematicDiagramClass As ISchematicDiagramClass = schematicDiagram.SchematicDiagramClass
            Dim schematicAttributeContainer As ISchematicAttributeContainer = schematicDiagramClass

            Dim schematicAttribute As ISchematicAttribute
            schematicAttribute = schematicAttributeContainer.GetSchematicAttribute("DigitizePropertiesLocation", True)

            If (schematicAttribute Is Nothing) Then
                MsgBox("Need an attribute named DigitizePropertiesLocation in the corresponding DiagramTemplate attributes")
                Return
            End If

            path = schematicAttribute.GetValue(schematicDiagram)


            If IsRelative(path) Then 'Concat the workspace's path with this path
                'current workspace path
                Dim myDataset As ISchematicDataset = schematicDiagramClass.SchematicDataset
                If Not myDataset Is Nothing Then
                    Dim mySchematicWorkspace As ISchematicWorkspace = myDataset.SchematicWorkspace
                    If Not mySchematicWorkspace Is Nothing Then
                        Dim myWorkspace As ESRI.ArcGIS.Geodatabase.IWorkspace = mySchematicWorkspace.Workspace
                        If Not myWorkspace Is Nothing Then
                            Dim workspacePath As String = myWorkspace.PathName
                            'add "..\" to path to step back one level...
                            Dim stepBack As String = "..\"
                            path = stepBack + path

                            path = System.IO.Path.Combine(workspacePath, path)

                        End If
                    End If
                End If
            End If
            'else keep the original hard path

            Dim reader As System.Xml.XmlReader = System.Xml.XmlReader.Create(path)

            m_dom.Load(reader)

            'Load Nodes
            Dim nodes As XmlNodeList = Nothing
            nodes = m_dom.SelectNodes("descendant::NodeFeature")

            cboNodeType.Items.Clear()
            Dim node As XmlElement = Nothing
            For Each node In nodes
                Me.cboNodeType.Items.Add(node.GetAttribute("FeatureClassName").ToString)
            Next

            'Load Links
            Dim links As XmlNodeList = Nothing
            links = m_dom.SelectNodes("descendant::LinkFeature")

            cboLinkType.Items.Clear()
            Dim link As XmlElement = Nothing
            For Each link In links
                Me.cboLinkType.Items.Add(link.GetAttribute("FeatureClassName").ToString)
            Next

            col = m_dom.SelectSingleNode("descendant::MandatoryColor")
            If Not col Is Nothing Then
                myString = "System.Drawing."
                myString = col.InnerText.ToString
                m_mandatoryColor = System.Drawing.Color.FromName(myString)
            End If

            col = m_dom.SelectSingleNode("descendant::FormName")
            If Not col Is Nothing Then
                myString = col.InnerText.ToString
                Me.Text = myString
            End If


            Dim rels As XmlNodeList = m_dom.SelectNodes("descendant::Relation")
            If rels.Count > 0 Then
                m_relations = rels
            End If

            col = m_dom.SelectSingleNode("descendant::AutoClearAfterCreate")
            If Not col Is Nothing Then
                If col.InnerText.ToString = "True" Then
                    m_autoClear = True
                End If
            End If
        Catch ex As Exception

        End Try

        m_Panel1 = Splitter.Panel1
        m_Panel2 = Splitter.Panel2
        m_curPanel = Splitter.Panel1
        lblMode.Text = "Create Node"
        m_loading = False
        m_clickPanel = False
        m_schEltClass = Nothing

    End Sub


    Public Function ValidateFields() As Boolean
        Dim blnValidated As Boolean = True
        Dim ctrl As Windows.Forms.Control = Nothing
        Dim mctrl As Windows.Forms.MaskedTextBox = Nothing
        Dim errors As String = ""

        'check all mandatory fields
        For Each ctrl In m_curPanel.Controls
            If TypeOf ctrl Is Windows.Forms.Label Then
                'ignore labels
            Else
                If ctrl.Tag = "Mandatory" Then
                    If TypeOf ctrl Is Windows.Forms.MaskedTextBox Then
                        mctrl = ctrl
                        If mctrl.MaskCompleted = False Then
                            blnValidated = False
                            If errors.Length > 0 Then
                                errors = "Incomplete mandatory field"
                            Else
                                errors = errors & vbCrLf & "Incomplete mandatory field"
                            End If
                        End If
                    Else
                        If Not ctrl.Text.Length > 0 Then
                            blnValidated = False
                            If errors.Length > 0 Then
                                errors = "Incomplete mandatory field"
                            Else
                                errors = errors & vbCrLf & "Incomplete mandatory field"
                            End If
                        End If
                    End If
                End If

                'check masked edit controls
                If TypeOf ctrl Is Windows.Forms.MaskedTextBox Then
                    mctrl = ctrl
                    'if they typed something, but didn't complete it, then error
                    'if they typed nothing and it is not mandatory, then it is OK
                    If mctrl.Text.Length > 0 Then
                        If mctrl.Modified = True Then
                            If mctrl.MaskCompleted = False Then
                                blnValidated = False
                                If errors.Length > 0 Then
                                    errors = "Invalid entry in a masked text field"
                                Else
                                    errors = errors & vbCrLf & "Invalid entry in a masked text field"
                                End If
                            End If
                        End If
                    End If
                End If
                'End If

                'check link connections
                If m_curPanel Is Splitter.Panel2 Then
                    'make sure that the relation is correct if it exists
                    Dim fields As XmlNodeList = m_curLink.SelectNodes("descendant::Field")
                    Dim field As XmlElement = Nothing
                    For Each field In fields
                        'find the field with a type of "Relation"
                        If field.GetAttribute("Type") = "Relation" Then
                            Dim rel As XmlElement = Nothing

                            Dim dataset1 As ESRI.ArcGIS.Geodatabase.IDataset
                            Dim dataset2 As ESRI.ArcGIS.Geodatabase.IDataset

                            Dim FeatureClass1Name As String
                            Dim FeatureClass2Name As String

                            dataset1 = m_schematicFeature1.SchematicElementClass
                            dataset2 = m_schematicFeature2.SchematicElementClass

                            FeatureClass1Name = dataset1.Name
                            FeatureClass2Name = dataset2.Name

                            For Each rel In m_relations
                                'loop through the xml relations to match based on the from node and to node types

                                If rel.GetAttribute("FromType") = FeatureClass1Name And rel.GetAttribute("ToType") = FeatureClass2Name Then
                                    'find the control with the pick list for relationships
                                    Dim ctrls() As Windows.Forms.Control = m_curPanel.Controls.Find(field.GetAttribute("DBColumnName"), True)
                                    If ctrls.Length > 0 Then
                                        ctrl = ctrls(0)
                                    End If
                                    Dim vals As XmlNodeList = rel.SelectNodes("descendant::Value")
                                    Dim val As XmlElement = Nothing
                                    Dim myString As String = rel.GetAttribute("FromType") & "-" & rel.GetAttribute("ToType")
                                    'validate that the current control string is correct
                                    'if there are values, use them
                                    Dim blnfound As Boolean = False
                                    If vals.Count > 0 Then
                                        For Each val In vals
                                            If myString & "-" & val.InnerText.ToString = ctrl.Text Then
                                                blnfound = True
                                                Exit For
                                            Else
                                                blnfound = False
                                            End If
                                        Next
                                        If blnfound = False Then
                                            blnValidated = False
                                            If errors.Length > 0 Then
                                                errors = "Invalid link connection"
                                            Else
                                                errors = errors & vbCrLf & "Invalid link connection"
                                            End If
                                        End If
                                    Else
                                        If ctrl.Text <> myString Then
                                            blnValidated = False
                                            If errors.Length > 0 Then
                                                errors = "Invalid link connection"
                                            Else
                                                errors = errors & vbCrLf & "Invalid link connection"
                                            End If
                                        End If
                                    End If
                                    If blnfound = False Then 'fix connection list
                                        Dim vlist As XmlNodeList = m_dom.SelectNodes("descendant::Relation")
                                        Dim v As XmlElement
                                        Dim rellist As XmlNodeList = Nothing
                                        Dim r As XmlElement = Nothing
                                        Dim cboconn As Windows.Forms.ComboBox = ctrl
                                        cboconn.Items.Clear()
                                        For Each v In vlist
                                            If v.GetAttribute("LinkType").ToString = m_curLink.GetAttribute("FeatureClassName").ToString Then
                                                'make sure the node types are ok
                                                If v.GetAttribute("FromType").ToString = FeatureClass1Name And v.GetAttribute("ToType").ToString = FeatureClass2Name Then    'ToString ??
                                                    rellist = v.SelectNodes("descendant::Value")
                                                    If rellist.Count > 0 Then    '
                                                        For Each r In rellist
                                                            myString = v.GetAttribute("FromType").ToString & "-" & v.GetAttribute("ToType").ToString & "-" & r.InnerText.ToString
                                                            cboconn.Items.Add(myString)
                                                        Next
                                                    Else 'assume they are not using subtypes
                                                        cboconn.Items.Add(v.GetAttribute("FromType").ToString & "-" & v.GetAttribute("ToType").ToString)
                                                    End If
                                                End If
                                            End If
                                        Next
                                    End If
                                End If
                            Next
                        End If
                    Next
                End If
            End If
        Next

        If errors.Length > 0 Then

            If m_curPanel Is Splitter.Panel1 Then
                btnOKPanel1.Visible = True

                ErrorProvider1.SetError(btnOKPanel1, errors)
            Else
                btnOKPanel2.Visible = True
                ErrorProvider1.SetError(btnOKPanel2, errors)
            End If
        End If
        Return blnValidated
    End Function

    Public Sub cboType_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboNodeType.SelectedValueChanged
        SelectionChanged()
    End Sub


    Public Sub SelectionChanged()
        Try
            Dim ctrl As System.Windows.Forms.Control = Nothing
            Dim ctrl2 As System.Windows.Forms.Control = Nothing
            Dim ctrls() As Object = Nothing
            Dim ctrlstoremove As Collection = New Collection
            Dim labelName As String = ""
            Dim featureClass As String = ""
            Dim cbo As Windows.Forms.ComboBox = Nothing
            Dim lblMain As Windows.Forms.Label = Nothing

            If m_digitCommand Is Nothing Then
                Return
            End If

            'clear any current elements
            If Not m_schematicFeature1 Is Nothing Then
                m_schematicFeature1 = Nothing
                m_digitCommand.SchematicFeature1() = m_schematicFeature1
            End If
            If Not m_schematicFeature2 Is Nothing Then
                m_schematicFeature2 = Nothing
                m_digitCommand.SchematicFeature2() = m_schematicFeature2
            End If

            If m_curPanel Is Splitter.Panel1 Then
                labelName = "lblNodeLabel"
                featureClass = "descendant::NodeFeature"
                cbo = cboNodeType
                lblMain = lblNodeLabel
            Else
                labelName = "lblLinkLabel"
                featureClass = "descendant::LinkFeature"
                cbo = cboLinkType
                lblMain = lblLinkLabel
            End If

            For Each ctrl In m_curPanel.Controls
                If ctrl.Name.StartsWith("lbl") And ctrl.Name.ToString <> labelName Then
                    ctrls = m_curPanel.Controls.Find(ctrl.Name.Substring(3), True)
                    ctrl2 = ctrls(0)
                    ctrlstoremove.Add(ctrl)
                    ctrlstoremove.Add(ctrl2)
                End If
            Next

            If ctrlstoremove.Count > 0 Then
                Dim ctrol As System.Windows.Forms.Control
                For Each ctrol In ctrlstoremove
                    m_curPanel.Controls.Remove(ctrol)
                    ctrol = Nothing
                Next
            End If

            Dim elem As XmlElement = Nothing
            Dim elems As XmlNodeList = Nothing
            m_curfrmWidth = m_curPanel.Width
            elems = m_dom.SelectNodes(featureClass)

            Dim blnFound As Boolean = False
            For Each elem In elems
                If elem.GetAttribute("FeatureClassName").ToString = cbo.Text.ToString Then
                    blnFound = True
                    Exit For
                End If
            Next
            If blnFound = False Then
                m_schEltClass = Nothing
                Exit Sub
            End If

            If m_curPanel Is Splitter.Panel1 Then
                m_curNode = elem
            Else
                m_curLink = elem
            End If

            'set grid
            elems = elem.SelectNodes("descendant::Field")
            Dim f As XmlElement
            Dim x As Integer = Splitter.Location.X
            Dim y As Integer = lblMain.Location.Y + lblMain.Height + 5

            Dim p As New System.Drawing.Point

            Dim rcount As Integer = 1
            For Each f In elems
                Dim lbl As New System.Windows.Forms.Label
                lbl.Name = "lbl" & f.GetAttribute("DBColumnName").ToString
                lbl.Text = f.GetAttribute("DisplayName").ToString
                lbl.AutoSize = True
                m_curPanel.Controls.Add(lbl)
                p.X = 3
                p.Y = y
                lbl.Location = p
                y = y + lbl.Height + 10
                Select Case f.GetAttribute("Type").ToString
                    Case "Text"
                        Dim tx As New System.Windows.Forms.TextBox
                        ctrl = tx
                        tx.Name = f.GetAttribute("DBColumnName").ToString
                        If f.GetAttribute("Length").Length > 0 Then
                            tx.MaxLength = CInt(f.GetAttribute("Length"))
                        End If
                        If f.GetAttribute("Default").Length > 0 Then
                            tx.Text = f.GetAttribute("Default")
                        End If
                        m_curPanel.Controls.Add(tx)

                    Case "Combo"
                        Dim cb As New System.Windows.Forms.ComboBox
                        Dim defaulttext As String = ""
                        ctrl = cb
                        cb.DropDownStyle = Windows.Forms.ComboBoxStyle.DropDownList
                        cb.Name = f.GetAttribute("DBColumnName").ToString
                        Dim vlist As XmlNodeList = f.SelectNodes("descendant::Value")
                        Dim v As XmlElement
                        For Each v In vlist
                            cb.Items.Add(v.InnerText.ToString)
                            If v.GetAttribute("Default").Length > 0 Then
                                defaulttext = v.InnerText
                            End If
                        Next
                        If defaulttext.Length > 0 Then
                            cb.Text = defaulttext
                        End If
                        m_curPanel.Controls.Add(cb)

                    Case "MaskText"
                        Dim MaskControl As New System.Windows.Forms.MaskedTextBox
                        ctrl = MaskControl
                        Dim mask As String = ""
                        MaskControl.Name = f.GetAttribute("DBColumnName").ToString
                        If f.GetAttribute("Mask").Length > 0 Then
                            mask = f.GetAttribute("Mask")
                        Else
                            mask = ""
                        End If
                        MaskControl.Mask = mask
                        If f.GetAttribute("Default").Length > 0 Then
                            MaskControl.Text = f.GetAttribute("Default")
                        End If
                        MaskControl.Modified = False
                        m_curPanel.Controls.Add(MaskControl)
                        AddHandler MaskControl.TextChanged, AddressOf MaskedTextBox

                    Case "Number"
                        Dim MaskControl As New System.Windows.Forms.MaskedTextBox
                        ctrl = MaskControl
                        Dim mask As String = ""
                        MaskControl.Name = f.GetAttribute("DBColumnName").ToString
                        Dim i As Int16 = 1
                        If f.GetAttribute("Length").Length > 0 Then
                            For i = 1 To CInt(f.GetAttribute("Length"))
                                mask = mask & "9"
                            Next
                        Else
                            If f.GetAttribute("Mask").Length > 0 Then
                                mask = f.GetAttribute("Mask")
                            Else
                                mask = ""
                            End If
                        End If
                        MaskControl.Mask = mask
                        If f.GetAttribute("Default").Length > 0 Then
                            MaskControl.Text = CInt(f.GetAttribute("Default"))
                        End If
                        MaskControl.Modified = False
                        m_curPanel.Controls.Add(MaskControl)
                        AddHandler MaskControl.TextChanged, AddressOf MaskedTextBox

                    Case "Date"
                        Dim dt As New System.Windows.Forms.DateTimePicker
                        ctrl = dt
                        dt.Name = f.GetAttribute("DBColumnName").ToString
                        dt.Value = Now.Date
                        dt.Format = Windows.Forms.DateTimePickerFormat.Short
                        m_curPanel.Controls.Add(dt)

                    Case "Relation"
                        Dim cb As New System.Windows.Forms.ComboBox
                        ctrl = cb
                        cb.DropDownStyle = Windows.Forms.ComboBoxStyle.DropDownList
                        cb.Name = f.GetAttribute("DBColumnName").ToString
                        Dim vlist As XmlNodeList = m_dom.SelectNodes("descendant::Relation")
                        Dim v As XmlElement
                        Dim rellist As XmlNodeList = Nothing
                        Dim r As XmlElement = Nothing
                        Dim myString As String = Nothing
                        For Each v In vlist
                            If v.GetAttribute("LinkType").ToString = elem.GetAttribute("FeatureClassName").ToString Then
                                rellist = v.SelectNodes("descendant::Value")
                                If rellist.Count > 0 Then    '
                                    For Each r In rellist
                                        myString = v.GetAttribute("FromType").ToString & "-" & v.GetAttribute("ToType").ToString & "-" & r.InnerText.ToString
                                        cb.Items.Add(myString)
                                    Next
                                Else 'assume they are not using subtypes
                                    cb.Items.Add(v.GetAttribute("FromType").ToString & "-" & v.GetAttribute("ToType").ToString)
                                End If
                            End If
                        Next
                        'relations are always mandatory
                        ctrl.BackColor = m_mandatoryColor
                        ctrl.Tag = "Mandatory"
                        m_curPanel.Controls.Add(cb)

                End Select
                If f.GetAttribute("Mandatory").ToString = "True" Then
                    ctrl.BackColor = m_mandatoryColor
                    ctrl.Tag = "Mandatory"
                End If
            Next
            ResizeForm()

            ' set m_schEltClass
            Dim schElement As ISchematicElement = Nothing
            Dim curElement As XmlElement = Nothing

            If m_curPanel Is Splitter.Panel1 Then
                curElement = m_curNode
            Else
                curElement = m_curLink
            End If

            If m_schEltClass Is Nothing Then
                m_schEltClass = m_schEltClassCont.GetSchematicElementClass(curElement.GetAttribute("FeatureClassName"))
            Else
                If m_schEltClass.Name <> curElement.GetAttribute("FeatureClassName") Then
                    m_schEltClass = m_schEltClassCont.GetSchematicElementClass(curElement.GetAttribute("FeatureClassName"))
                End If
            End If


        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub


    Public Function CheckValidFeature(ByVal blnFromNode As Boolean) As Boolean

        If m_curLink Is Nothing Then
            Return False
        End If

        Dim fields As XmlNodeList = m_curLink.SelectNodes("descendant::Field")
        Dim field As XmlElement = Nothing
        For Each field In fields
            If field.GetAttribute("Type") = "Relation" Then
                Dim rel As XmlElement = Nothing
                For Each rel In m_relations
                    If blnFromNode = True Then
                        If m_schematicFeature1 Is Nothing Then
                            Return False
                        End If
                        If rel.GetAttribute("FromType") = m_schematicFeature1.SchematicElementClass.Name Then
                            Return True
                        End If
                    Else
                        If m_schematicFeature2 Is Nothing Then
                            Return False
                        End If
                        If rel.GetAttribute("ToType") = m_schematicFeature2.SchematicElementClass.Name Then
                            Return True
                        End If
                    End If
                Next
                Return False
            End If
        Next
        Return True
    End Function

    Private Sub frmDigitize_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        If m_loading = False Then
            ResizeForm()
        End If
    End Sub

    Private Sub ResizeForm()
        Try
            Dim ctr As System.Windows.Forms.Control
            Dim ctr2 As System.Windows.Forms.Control
            Dim ctrls() As Object
            Dim p As System.Drawing.Point
            'handle panel 1
            For Each ctr In Splitter.Panel1.Controls
                If ctr.Name.StartsWith("lbl") And ctr.Name.ToString <> "lblNodeLabel" Then
                    'ctr.Width = Splitter.panel1.Width / 3
                    'MsgBox(ctr.Name.Substring(3))
                    ctrls = Splitter.Panel1.Controls.Find(ctr.Name.Substring(3), True)
                    If ctrls.GetLength(0) > 0 Then
                        ctr2 = ctrls(0)

                        p.Y = ctr.Location.Y
                        p.X = ctr.Width + 3
                        ctr2.Location = p
                        ctr2.Width = Splitter.Panel1.Width - ctr.Width - 5
                    End If
                End If
            Next
            Splitter.Panel1.Refresh()
            'handle panel 2
            For Each ctr In Splitter.Panel2.Controls
                If ctr.Name.StartsWith("lbl") And ctr.Name.ToString <> "lblLinkLabel" Then
                    'ctr.Width = Splitter.panel1.Width / 3
                    'MsgBox(ctr.Name.Substring(3))
                    ctrls = Splitter.Panel2.Controls.Find(ctr.Name.Substring(3), True)
                    If ctrls.GetLength(0) > 0 Then
                        ctr2 = ctrls(0)
                        p.Y = ctr.Location.Y
                        p.X = ctr.Width + 3
                        ctr2.Location = p
                        ctr2.Width = Splitter.Panel2.Width - ctr.Width - 5
                    End If
                End If
            Next
            Splitter.Panel2.Refresh()
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    Private Sub cboLinkType_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboLinkType.SelectedValueChanged
        SelectionChanged()
    End Sub

    Public Sub FillValue(ByRef schFeature As ISchematicFeature)

        Try

            If m_schEltClass Is Nothing Then
                Err.Raise(513, "CreateNewFeature", "Error getting Feature Class")
            End If

            Dim fldIndex As Int16 = Nothing

            Dim ctrl As Windows.Forms.Control = Nothing
            For Each ctrl In m_curPanel.Controls
                If TypeOf ctrl Is Windows.Forms.Label Or ctrl.Name = "cboNodeType" Then
                    'do nothing
                Else
                    If TypeOf ctrl Is Windows.Forms.TextBox Or TypeOf ctrl Is Windows.Forms.ComboBox Then
                        If ctrl.Text.Length > 0 Then
                            'insert in DB
                            fldIndex = schFeature.Fields.FindField(ctrl.Name)
                            If (fldIndex > -1) Then
                                schFeature.Value(fldIndex) = ctrl.Text
                                schFeature.Store()
                            End If
                        End If
                    ElseIf TypeOf ctrl Is Windows.Forms.DateTimePicker Then
                        fldIndex = schFeature.Fields.FindField(ctrl.Name)
                        If (fldIndex > -1) Then
                            schFeature.Value(fldIndex) = ctrl.Text
                            schFeature.Store()
                        End If

                    ElseIf TypeOf ctrl Is Windows.Forms.MaskedTextBox Then
                        Dim mctrl As Windows.Forms.MaskedTextBox = ctrl
                        If mctrl.Text.Length > 0 Then
                            If mctrl.Modified = True Then
                                If mctrl.MaskCompleted = True Then
                                    fldIndex = schFeature.Fields.FindField(ctrl.Name)
                                    If (fldIndex > -1) Then
                                        schFeature.Value(fldIndex) = ctrl.Text
                                        schFeature.Store()
                                    End If
                                End If
                            End If
                        End If

                    End If

                End If
            Next

            Return

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub


    Private Sub btnOKPanel1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOKPanel1.Click
        'try to create the node at the original point
        If Not m_digitCommand Is Nothing Then
            m_digitCommand.MyMouseUp(m_x, m_y)
        End If

        ErrorProvider1.SetError(btnOKPanel1, "")
        btnOKPanel1.Visible = False
    End Sub

    Private Sub btnOKPanel2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOKPanel2.Click
        'try to create the link with the original points
        m_digitCommand.MyMouseUp(m_x, m_y)

        ErrorProvider1.SetError(btnOKPanel1, "")
        btnOKPanel1.Visible = False
    End Sub

    Private Sub MaskedTextBox(ByVal sender As Object, ByVal e As EventArgs)
        Dim mctrl As Windows.Forms.MaskedTextBox = sender
        mctrl.Modified = True
    End Sub

    Private Sub WindowVisibleChange() Handles Me.VisibleChanged

        If (m_digitCommand Is Nothing) Then
            m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit
        End If

        If (m_digitCommand Is Nothing) Then
            Return
        End If

        If Me.Visible = True And CurrentDigitTool.CurrentTool.currentDockableWindow.IsVisible() = False Then
            If m_digitCommand.FromDeactivate = False Then
                m_digitCommand.DeactivatedFromDock = True

                Dim app As ESRI.ArcGIS.Framework.IApplication = Me.Hook
                app.CurrentTool = Nothing
            End If
        End If

        m_digitCommand.EndFeedBack()
        m_digitCommand.FromDeactivate = False

    End Sub

    Friend ReadOnly Property CreateNode() As Boolean
        Get
            Return m_createNode
        End Get
    End Property

    Friend ReadOnly Property AutoClear() As Boolean
        Get
            Return m_autoClear
        End Get
    End Property

    Friend ReadOnly Property FeatureClass() As ISchematicElementClass
        Get
            Return m_schEltClass
        End Get
    End Property

    Public WriteOnly Property x() As Integer
        Set(ByVal Value As Integer)
            m_x = Value
        End Set
    End Property

    Public WriteOnly Property y() As Integer
        Set(ByVal Value As Integer)
            m_y = Value
        End Set
    End Property

    Public WriteOnly Property SchematicFeature1() As ISchematicFeature
        Set(ByVal Value As ISchematicFeature)
            m_schematicFeature1 = Value
        End Set
    End Property

    Public WriteOnly Property SchematicFeature2() As ISchematicFeature
        Set(ByVal Value As ISchematicFeature)
            m_schematicFeature2 = Value
        End Set
    End Property

    'IsRelative return true when the path start with "."
    Private Function IsRelative(ByVal path As String) As Boolean
        If path(0) = "." Then
            Return True
        Else
            Return False
        End If
    End Function

    Private Sub cboNodeType_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboNodeType.SelectedIndexChanged
        SelectionChanged()
    End Sub


    Private Sub Splitter_Panel1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Splitter.Panel1.Click
        If (m_digitCommand Is Nothing) Then
            m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit
        End If

        If Not m_digitCommand Is Nothing Then
            m_digitCommand.EndFeedBack()
        End If

        m_createNode = True

        If (Not m_curPanel Is Splitter.Panel1) Or (m_clickPanel = False) Then

            m_clickPanel = True

            Dim ctrl As Windows.Forms.Control
            m_curPanel = Splitter.Panel1
            For Each ctrl In Splitter.Panel2.Controls
                ctrl.Enabled = False
            Next
            For Each ctrl In Splitter.Panel1.Controls
                ctrl.Enabled = True
            Next
            lblMode.Text = "Create Node"

            If m_curPanel Is Splitter.Panel1 Then
                btnOKPanel1.Visible = False
                ErrorProvider1.SetError(btnOKPanel1, "")
            Else
                btnOKPanel2.Visible = False
                ErrorProvider1.SetError(btnOKPanel2, "")
            End If
            Dim e2 As New System.EventArgs
            cboType_SelectedValueChanged(sender, e2)
        End If
    End Sub

    Private Sub Splitter_Panel2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Splitter.Panel2.Click
        If (m_digitCommand Is Nothing) Then
            m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit
        End If

        If m_digitCommand Is Nothing Then
            Return
        End If

        m_createNode = False

        If Not m_curPanel Is Splitter.Panel2 Then
            Dim ctrl As Windows.Forms.Control
            m_curPanel = Splitter.Panel2
            For Each ctrl In Splitter.Panel1.Controls
                ctrl.Enabled = False
            Next
            For Each ctrl In Splitter.Panel2.Controls
                ctrl.Enabled = True
            Next
            lblMode.Text = "Create Link"

            If Not m_schematicFeature1 Is Nothing Then
                m_schematicFeature1 = Nothing
                m_digitCommand.SchematicFeature1() = m_schematicFeature1
            End If
            If Not m_schematicFeature2 Is Nothing Then
                m_schematicFeature2 = Nothing
                m_digitCommand.SchematicFeature2() = m_schematicFeature2
            End If

            If m_curPanel Is Splitter.Panel1 Then
                btnOKPanel1.Visible = False
                ErrorProvider1.SetError(btnOKPanel1, "")
            Else
                btnOKPanel2.Visible = False
                ErrorProvider1.SetError(btnOKPanel2, "")
            End If
            Dim e2 As New System.EventArgs
            cboLinkType_SelectedValueChanged(sender, e2)
        End If
    End Sub
End Class