Exemple #1
0
        /// <summary>
        /// Обновить сигналы КП элементов групп, начиная с заданного узла дерева
        /// </summary>
        private void UpdateSignals(TreeNode startGrNode)
        {
            // проверка корректности заданного узла дерева
            if (!(startGrNode.Tag is Modbus.ElemGroup))
            {
                return;
            }

            // определение начального индекса тегов КП
            TreeNode prevGrNode = startGrNode.PrevNode;

            Modbus.ElemGroup prevElemGroup = prevGrNode == null ? null : prevGrNode.Tag as Modbus.ElemGroup;
            int tagInd = prevElemGroup == null ? 0 : prevElemGroup.StartKPTagInd + prevElemGroup.Elems.Count;

            // обновление групп и их элементов
            int grNodeCnt = grsNode.Nodes.Count;

            for (int i = startGrNode.Index; i < grNodeCnt; i++)
            {
                TreeNode         grNode    = grsNode.Nodes[i];
                Modbus.ElemGroup elemGroup = grNode.Tag as Modbus.ElemGroup;
                int elemSig = tagInd + 1;
                elemGroup.StartKPTagInd = tagInd;
                tagInd += elemGroup.Elems.Count;

                foreach (TreeNode elemNode in grNode.Nodes)
                {
                    ElemInfo elem = elemNode.Tag as ElemInfo;
                    elem.Signal = elemSig++;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Создать узел группы элементов
        /// </summary>
        private TreeNode NewElemGroupNode(Modbus.ElemGroup elemGroup)
        {
            string   name   = elemGroup.Name == "" ? KpPhrases.DefGrName : elemGroup.Name;
            TreeNode grNode = new TreeNode(name + " (" + Modbus.GetTableTypeName(elemGroup.TableType) + ")");

            grNode.ImageKey = grNode.SelectedImageKey = "group.png";
            grNode.Tag      = elemGroup;

            ushort elemAddr = elemGroup.Address;
            int    elemSig  = elemGroup.StartKPTagInd + 1;

            foreach (Modbus.Elem elem in elemGroup.Elems)
            {
                ElemInfo elemInfo = new ElemInfo();
                elemInfo.Elem      = elem;
                elemInfo.ElemGroup = elemGroup;
                elemInfo.Address   = elemAddr;
                elemInfo.Signal    = elemSig++;

                grNode.Nodes.Add(NewElemNode(elemInfo));
                elemAddr += (ushort)elem.Length;
            }

            return(grNode);
        }
Exemple #3
0
        /// <summary>
        /// Обновить узлы элементов выбранной группы
        /// </summary>
        private void UpdateElemNodes(TreeNode grNode = null)
        {
            treeView.BeginUpdate();

            if (grNode == null)
            {
                grNode = selNode;
            }

            if (grNode.Tag is Modbus.ElemGroup)
            {
                Modbus.ElemGroup elemGroup = (Modbus.ElemGroup)grNode.Tag;
                ushort           elemAddr  = elemGroup.Address;
                int elemSig = elemGroup.StartKPTagInd + 1;

                foreach (TreeNode elemNode in grNode.Nodes)
                {
                    ElemInfo elemInfo = elemNode.Tag as ElemInfo;
                    elemInfo.Address = elemAddr;
                    elemInfo.Signal  = elemSig++;
                    elemNode.Text    = elemInfo.Caption;
                    elemAddr        += (ushort)elemInfo.Elem.Length;
                }
            }

            treeView.EndUpdate();
        }
Exemple #4
0
        /// <summary>
        /// Создать узел элемента группы
        /// </summary>
        private TreeNode NewElemNode(ElemInfo elemInfo)
        {
            TreeNode elemNode = new TreeNode(elemInfo.Caption);

            elemNode.ImageKey = elemNode.SelectedImageKey = "elem.png";
            elemNode.Tag      = elemInfo;
            return(elemNode);
        }
Exemple #5
0
        /// <summary>
        /// Отобразить свойства элемента
        /// </summary>
        private void ShowElemProps(ElemInfo elemInfo)
        {
            procChangedEv = false;

            gbElemGroup.Visible = false;
            gbElem.Visible      = true;
            gbCmd.Visible       = false;

            if (elemInfo == null)
            {
                txtElemName.Text    = "";
                txtElemAddress.Text = "";
                txtElemSignal.Text  = "";
                rbBool.Checked      = true;
                gbElem.Enabled      = false;
            }
            else
            {
                txtElemName.Text    = elemInfo.Elem.Name;
                txtElemAddress.Text = elemInfo.AddressRange;
                txtElemSignal.Text  = elemInfo.Signal.ToString();
                Modbus.ElemTypes elemType = elemInfo.Elem.ElemType;
                rbUShort.Enabled = rbShort.Enabled = rbUInt.Enabled = rbInt.Enabled = rbFloat.Enabled =
                    elemType != Modbus.ElemTypes.Bool;
                rbBool.Enabled = elemType == Modbus.ElemTypes.Bool;

                switch (elemType)
                {
                case Modbus.ElemTypes.UShort:
                    rbUShort.Checked = true;
                    break;

                case Modbus.ElemTypes.Short:
                    rbShort.Checked = true;
                    break;

                case Modbus.ElemTypes.UInt:
                    rbUInt.Checked = true;
                    break;

                case Modbus.ElemTypes.Int:
                    rbInt.Checked = true;
                    break;

                case Modbus.ElemTypes.Float:
                    rbFloat.Checked = true;
                    break;

                default:
                    rbBool.Checked = true;
                    break;
                }

                gbElem.Enabled = true;
            }

            procChangedEv = true;
        }
Exemple #6
0
        private void btnMoveDown_Click(object sender, EventArgs e)
        {
            // перемещение объекта вниз
            TreeNode nextNode = selNode.NextNode;
            int      nextInd  = nextNode.Index;

            if (selElemGroup != null)
            {
                // перемещение группы элементов вниз
                Modbus.ElemGroup nextElemGroup = nextNode.Tag as Modbus.ElemGroup;

                devTemplate.ElemGroups.RemoveAt(nextInd);
                devTemplate.ElemGroups.Insert(nextInd - 1, nextElemGroup);

                grsNode.Nodes.RemoveAt(nextInd);
                grsNode.Nodes.Insert(nextInd - 1, nextNode);

                UpdateSignals(nextNode);
            }
            else if (selElemInfo != null)
            {
                // перемещение элемента вниз
                ElemInfo nextElemInfo = nextNode.Tag as ElemInfo;

                selElemInfo.ElemGroup.Elems.RemoveAt(nextInd);
                selElemInfo.ElemGroup.Elems.Insert(nextInd - 1, nextElemInfo.Elem);

                TreeNode grNode = selNode.Parent;
                grNode.Nodes.RemoveAt(nextInd);
                grNode.Nodes.Insert(nextInd - 1, nextNode);

                UpdateElemNodes(grNode);
                ShowElemProps(selElemInfo);
            }
            else if (selCmd != null)
            {
                // перемещение команды вниз
                Modbus.Cmd nextCmd = nextNode.Tag as Modbus.Cmd;

                devTemplate.Cmds.RemoveAt(nextInd);
                devTemplate.Cmds.Insert(nextInd - 1, nextCmd);

                cmdsNode.Nodes.RemoveAt(nextInd);
                cmdsNode.Nodes.Insert(nextInd - 1, nextNode);
            }

            // установка доступности кнопок
            btnMoveUp.Enabled   = selNode.PrevNode != null;
            btnMoveDown.Enabled = selNode.NextNode != null;

            // установка признака изменения
            Modified = true;
        }
Exemple #7
0
        private void numGrElemCnt_ValueChanged(object sender, EventArgs e)
        {
            // изменение количества элементов в группе
            if (procChangedEv && selElemGroup != null)
            {
                treeView.BeginUpdate();
                int elemCnt    = selElemGroup.Elems.Count;
                int newElemCnt = (int)numGrElemCnt.Value;

                if (elemCnt < newElemCnt)
                {
                    // добавление новых элементов
                    Modbus.ElemTypes elemType = selElemGroup.DefElemType;
                    ushort           elemLen  = (ushort)Modbus.Elem.GetElemLength(elemType);
                    ushort           elemAddr = selElemGroup.Address;

                    for (int elemInd = 0; elemInd < newElemCnt; elemInd++)
                    {
                        if (elemInd < elemCnt)
                        {
                            elemAddr += (ushort)selElemGroup.Elems[elemInd].Length;
                        }
                        else
                        {
                            ElemInfo elemInfo = new ElemInfo();
                            elemInfo.Elem = new Modbus.Elem()
                            {
                                ElemType = elemType
                            };
                            elemInfo.Address   = elemAddr;
                            elemInfo.ElemGroup = selElemGroup;

                            selElemGroup.Elems.Add(elemInfo.Elem);
                            selNode.Nodes.Add(NewElemNode(elemInfo));
                            elemAddr += elemLen;
                        }
                    }
                }
                else if (elemCnt > newElemCnt)
                {
                    // удаление лишних элементов
                    for (int i = newElemCnt; i < elemCnt; i++)
                    {
                        selElemGroup.Elems.RemoveAt(newElemCnt);
                        selNode.Nodes.RemoveAt(newElemCnt);
                    }
                }

                UpdateSignals(selNode);
                Modified = true;
                treeView.EndUpdate();
            }
        }
Exemple #8
0
        private bool procChangedEv;             // обрабатывать события на изменение данных


        /// <summary>
        /// Конструктор
        /// </summary>
        public FrmDevTemplate()
        {
            InitializeComponent();

            devTemplate   = new Modbus.DeviceModel();
            modified      = false;
            fileName      = "";
            selElemGroup  = null;
            selElemInfo   = null;
            selCmd        = null;
            selNode       = null;
            grsNode       = treeView.Nodes["grsNode"];
            cmdsNode      = treeView.Nodes["cmdsNode"];
            procChangedEv = false;

            ConfigDir = "";
            LangDir   = "";
        }
Exemple #9
0
        private TreeNode selNode; // выбранный узел дерева

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Конструктор
        /// </summary>
        public FrmDevTemplate()
        {
            InitializeComponent();

            devTemplate = new Modbus.DeviceModel();
            modified = false;
            fileName = "";
            selElemGroup = null;
            selElemInfo = null;
            selCmd = null;
            selNode = null;
            grsNode = treeView.Nodes["grsNode"];
            cmdsNode = treeView.Nodes["cmdsNode"];
            procChangedEv = false;

            ConfigDir = "";
            LangDir = "";
        }
Exemple #10
0
        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // отображение выбранного объекта и его свойств
            selNode = e.Node;
            object tag = selNode.Tag;

            selElemGroup = tag as Modbus.ElemGroup;
            selElemInfo  = tag as ElemInfo;
            selCmd       = tag as Modbus.Cmd;

            if (selElemGroup != null)
            {
                ShowElemGroupProps(selElemGroup);
            }
            else if (selElemInfo != null)
            {
                ShowElemProps(selElemInfo);
            }
            else if (selCmd != null)
            {
                ShowCmdProps(selCmd);
            }
            else if (selNode == grsNode)
            {
                ShowElemGroupProps(null);
            }
            else if (selNode == cmdsNode)
            {
                ShowCmdProps(null);
            }
            else // не выполняется
            {
                DisableProps();
            }

            // установка доступности кнопок
            btnAddElem.Enabled = selElemGroup != null || selElemInfo != null;
            bool nodeIsOk = selElemGroup != null || selCmd != null ||
                            selElemInfo != null && selElemInfo.ElemGroup.Elems.Count > 1 /*последний не удалять*/;

            btnMoveUp.Enabled   = nodeIsOk && selNode.PrevNode != null;
            btnMoveDown.Enabled = nodeIsOk && selNode.NextNode != null;
            btnDelete.Enabled   = nodeIsOk;
        }
Exemple #11
0
        private bool procChangedEv;             // обрабатывать события на изменение данных


        /// <summary>
        /// Конструктор, ограничивающий создание формы без параметров
        /// </summary>
        private FrmDevTemplate()
        {
            InitializeComponent();

            appDirs         = null;
            initialFileName = "";
            fileName        = "";
            saveOnly        = false;

            devTemplate   = null;
            modified      = false;
            selElemGroup  = null;
            selElemInfo   = null;
            selCmd        = null;
            selNode       = null;
            grsNode       = treeView.Nodes["grsNode"];
            cmdsNode      = treeView.Nodes["cmdsNode"];
            procChangedEv = false;
        }
Exemple #12
0
        private TreeNode selNode; // выбранный узел дерева

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Конструктор, ограничивающий создание формы без параметров
        /// </summary>
        private FrmDevTemplate()
        {
            InitializeComponent();

            appDirs = null;
            initialFileName = "";
            fileName = "";
            saveOnly = false;

            devTemplate = null;
            modified = false;
            selElemGroup = null;
            selElemInfo = null;
            selCmd = null;
            selNode = null;
            grsNode = treeView.Nodes["grsNode"];
            cmdsNode = treeView.Nodes["cmdsNode"];
            procChangedEv = false;
        }
Exemple #13
0
        private void btnAddElem_Click(object sender, EventArgs e)
        {
            // создание элемента и добавление в шаблон устройства
            Modbus.ElemGroup elemGroup = selElemGroup == null ? selElemInfo.ElemGroup : selElemGroup;
            int maxElemCnt             = Modbus.ElemGroup.GetMaxElemCnt(elemGroup.TableType);

            if (elemGroup.Elems.Count >= maxElemCnt)
            {
                MessageBox.Show(string.Format(KpPhrases.ElemCntExceeded, maxElemCnt),
                                CommonPhrases.WarningCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            ElemInfo elemInfo = new ElemInfo();

            elemInfo.Elem = new Modbus.Elem()
            {
                ElemType = elemGroup.DefElemType
            };
            elemInfo.ElemGroup = elemGroup;
            int ind = selNode.Tag is ElemInfo ? selNode.Index + 1 : elemGroup.Elems.Count;

            elemGroup.Elems.Insert(ind, elemInfo.Elem);

            // создание узла дерева элемента
            TreeNode elemNode = NewElemNode(elemInfo);
            TreeNode grNode   = selNode.Tag is ElemInfo ? selNode.Parent : selNode;

            grNode.Nodes.Insert(ind, elemNode);
            UpdateElemNodes(grNode);
            UpdateSignals(grNode);
            treeView.SelectedNode = elemNode;
            txtElemName.Select();

            // установка признака изменения
            Modified = true;
        }
Exemple #14
0
        /// <summary>
        /// Заполнить дерево в соответствии с шаблоном устройства
        /// </summary>
        private void FillTree()
        {
            // обнуление выбранных объектов и снятие признака изменения
            selElemGroup = null;
            selElemInfo  = null;
            selCmd       = null;
            selNode      = null;
            ShowElemGroupProps(null);
            Modified = false;

            // приостановка отрисовки дерева
            treeView.BeginUpdate();

            // очистка дерева
            grsNode.Nodes.Clear();
            cmdsNode.Nodes.Clear();
            treeView.SelectedNode = grsNode;

            // заполнение узла групп элементов
            foreach (Modbus.ElemGroup elemGroup in devTemplate.ElemGroups)
            {
                grsNode.Nodes.Add(NewElemGroupNode(elemGroup));
            }

            // заполнение узла команд
            foreach (Modbus.Cmd cmd in devTemplate.Cmds)
            {
                cmdsNode.Nodes.Add(NewCmdNode(cmd));
            }

            // раскрытие основных узлов дерева
            grsNode.Expand();
            cmdsNode.Expand();

            // возобновление отрисовки дерева
            treeView.EndUpdate();
        }
Exemple #15
0
        private void numGrElemCnt_ValueChanged(object sender, EventArgs e)
        {
            // изменение количества элементов в группе
            if (procChangedEv && selElemGroup != null)
            {
                treeView.BeginUpdate();
                int elemCnt = selElemGroup.Elems.Count;
                int newElemCnt = (int)numGrElemCnt.Value;

                if (elemCnt < newElemCnt)
                {
                    // добавление новых элементов
                    Modbus.ElemTypes elemType = selElemGroup.DefElemType;
                    ushort elemLen = (ushort)Modbus.Elem.GetElemLength(elemType);
                    ushort elemAddr = selElemGroup.Address;

                    for (int elemInd = 0; elemInd < newElemCnt; elemInd++)
                    {
                        if (elemInd < elemCnt)
                        {
                            elemAddr += (ushort)selElemGroup.Elems[elemInd].Length;
                        }
                        else
                        {
                            ElemInfo elemInfo = new ElemInfo();
                            elemInfo.Elem = new Modbus.Elem() { ElemType = elemType };
                            elemInfo.Address = elemAddr;
                            elemInfo.ElemGroup = selElemGroup;

                            selElemGroup.Elems.Add(elemInfo.Elem);
                            selNode.Nodes.Add(NewElemNode(elemInfo));
                            elemAddr += elemLen;
                        }
                    }
                }
                else if (elemCnt > newElemCnt)
                {
                    // удаление лишних элементов
                    for (int i = newElemCnt; i < elemCnt; i++)
                    {
                        selElemGroup.Elems.RemoveAt(newElemCnt);
                        selNode.Nodes.RemoveAt(newElemCnt);
                    }
                }

                UpdateSignals(selNode);
                Modified = true;
                treeView.EndUpdate();
            }
        }
 private void GrowElements()
 {
     int num = this.elementStack.Length * 2;
     ElemInfo[] destinationArray = new ElemInfo[num];
     Array.Copy(this.elementStack, 0, destinationArray, 0, this.elementStack.Length);
     this.elementStack = destinationArray;
 }
Exemple #17
0
        /// <summary>
        /// Заполнить дерево в соответствии с шаблоном устройства
        /// </summary>
        private void FillTree()
        {
            // обнуление выбранных объектов и снятие признака изменения
            selElemGroup = null;
            selElemInfo = null;
            selCmd = null;
            selNode = null;
            ShowElemGroupProps(null);
            Modified = false;

            // приостановка отрисовки дерева
            treeView.BeginUpdate();

            // очистка дерева
            grsNode.Nodes.Clear();
            cmdsNode.Nodes.Clear();
            treeView.SelectedNode = grsNode;

            // заполнение узла групп элементов
            foreach (Modbus.ElemGroup elemGroup in devTemplate.ElemGroups)
                grsNode.Nodes.Add(NewElemGroupNode(elemGroup));

            // заполнение узла команд
            foreach (Modbus.Cmd cmd in devTemplate.Cmds)
                cmdsNode.Nodes.Add(NewCmdNode(cmd));

            // раскрытие основных узлов дерева
            grsNode.Expand();
            cmdsNode.Expand();

            // возобновление отрисовки дерева
            treeView.EndUpdate();
        }
Exemple #18
0
        /// <summary>
        /// Создать узел группы элементов
        /// </summary>
        private TreeNode NewElemGroupNode(Modbus.ElemGroup elemGroup)
        {
            string name = elemGroup.Name == "" ? KpPhrases.DefGrName : elemGroup.Name;
            TreeNode grNode = new TreeNode(name + " (" + Modbus.GetTableTypeName(elemGroup.TableType) + ")");
            grNode.ImageKey = grNode.SelectedImageKey = "group.png";
            grNode.Tag = elemGroup;

            ushort elemAddr = elemGroup.Address;
            int elemSig = elemGroup.StartKPTagInd + 1;

            foreach (Modbus.Elem elem in elemGroup.Elems)
            {
                ElemInfo elemInfo = new ElemInfo();
                elemInfo.Elem = elem;
                elemInfo.ElemGroup = elemGroup;
                elemInfo.Address = elemAddr;
                elemInfo.Signal = elemSig++;

                grNode.Nodes.Add(NewElemNode(elemInfo));
                elemAddr += (ushort)elem.Length;
            }

            return grNode;
        }
Exemple #19
0
 /// <summary>
 /// Создать узел элемента группы
 /// </summary>
 private TreeNode NewElemNode(ElemInfo elemInfo)
 {
     TreeNode elemNode = new TreeNode(elemInfo.Caption);
     elemNode.ImageKey = elemNode.SelectedImageKey = "elem.png";
     elemNode.Tag = elemInfo;
     return elemNode;
 }
Exemple #20
0
        /// <summary>
        /// Отобразить свойства элемента
        /// </summary>
        private void ShowElemProps(ElemInfo elemInfo)
        {
            procChangedEv = false;

            gbElemGroup.Visible = false;
            gbElem.Visible = true;
            gbCmd.Visible = false;

            if (elemInfo == null)
            {
                txtElemName.Text = "";
                txtElemAddress.Text = "";
                txtElemSignal.Text = "";
                rbBool.Checked = true;
                txtByteOrder.Text = "";
                gbElem.Enabled = false;
            }
            else
            {
                txtElemName.Text = elemInfo.Elem.Name;
                txtElemAddress.Text = elemInfo.AddressRange;
                txtElemSignal.Text = elemInfo.Signal.ToString();
                Modbus.ElemTypes elemType = elemInfo.Elem.ElemType;

                if (elemType == Modbus.ElemTypes.Bool)
                {
                    rbUShort.Enabled = rbShort.Enabled = rbUInt.Enabled = rbInt.Enabled = 
                        rbULong.Enabled = rbLong.Enabled = rbFloat.Enabled = rbDouble.Enabled = false;
                    rbBool.Enabled = true;
                    txtByteOrder.Text = "";
                    txtByteOrder.Enabled = false;
                }
                else
                {
                    rbUShort.Enabled = rbShort.Enabled = rbUInt.Enabled = rbInt.Enabled =
                        rbULong.Enabled = rbLong.Enabled = rbFloat.Enabled = rbDouble.Enabled = true;
                    rbBool.Enabled = false;
                    txtByteOrder.Text = elemInfo.Elem.ByteOrderStr;
                    txtByteOrder.Enabled = true;
                }

                switch (elemType)
                {
                    case Modbus.ElemTypes.UShort:
                        rbUShort.Checked = true;
                        break;
                    case Modbus.ElemTypes.Short:
                        rbShort.Checked = true;
                        break;
                    case Modbus.ElemTypes.UInt:
                        rbUInt.Checked = true;
                        break;
                    case Modbus.ElemTypes.Int:
                        rbInt.Checked = true;
                        break;
                    case Modbus.ElemTypes.ULong:
                        rbULong.Checked = true;
                        break;
                    case Modbus.ElemTypes.Long:
                        rbLong.Checked = true;
                        break;
                    case Modbus.ElemTypes.Float:
                        rbFloat.Checked = true;
                        break;
                    case Modbus.ElemTypes.Double:
                        rbDouble.Checked = true;
                        break;
                    default:
                        rbBool.Checked = true;
                        break;
                }

                gbElem.Enabled = true;
            }

            procChangedEv = true;
        }
        void GrowElements() {
            int newcount = this.elementStack.Length * 2;
            ElemInfo[] n = new ElemInfo[newcount];

            System.Array.Copy(this.elementStack, 0, n, 0, this.elementStack.Length);
            this.elementStack = n;
        }
Exemple #22
0
        private void GrowElements()
        {
            int newcount = _elementStack.Length * 2;
            ElemInfo[] n = new ElemInfo[newcount];

            System.Array.Copy(_elementStack, 0, n, 0, _elementStack.Length);
            _elementStack = n;
        }
Exemple #23
0
        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // отображение выбранного объекта и его свойств
            selNode = e.Node;
            object tag = selNode.Tag;
            selElemGroup = tag as Modbus.ElemGroup;
            selElemInfo = tag as ElemInfo;
            selCmd = tag as Modbus.Cmd;

            if (selElemGroup != null)
                ShowElemGroupProps(selElemGroup);
            else if (selElemInfo != null)
                ShowElemProps(selElemInfo);
            else if (selCmd != null)
                ShowCmdProps(selCmd);
            else if (selNode == grsNode)
                ShowElemGroupProps(null);
            else if (selNode == cmdsNode)
                ShowCmdProps(null);
            else // не выполняется
                DisableProps();

            // установка доступности кнопок
            btnAddElem.Enabled = selElemGroup != null || selElemInfo != null;
            bool nodeIsOk = selElemGroup != null || selCmd != null ||
                selElemInfo != null && selElemInfo.ElemGroup.Elems.Count > 1 /*последний не удалять*/;
            btnMoveUp.Enabled = nodeIsOk && selNode.PrevNode != null;
            btnMoveDown.Enabled = nodeIsOk && selNode.NextNode != null;
            btnDelete.Enabled = nodeIsOk;
        }
Exemple #24
0
        private void btnAddElem_Click(object sender, EventArgs e)
        {
            // создание элемента и добавление в шаблон устройства
            Modbus.ElemGroup elemGroup = selElemGroup == null ? selElemInfo.ElemGroup : selElemGroup;
            int maxElemCnt = Modbus.ElemGroup.GetMaxElemCnt(elemGroup.TableType);

            if (elemGroup.Elems.Count >= maxElemCnt)
            {
                MessageBox.Show(string.Format(KpPhrases.ElemCntExceeded, maxElemCnt), 
                    CommonPhrases.WarningCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            ElemInfo elemInfo = new ElemInfo();
            elemInfo.Elem = new Modbus.Elem() { ElemType = elemGroup.DefElemType };
            elemInfo.ElemGroup = elemGroup;
            int ind = selNode.Tag is ElemInfo ? selNode.Index + 1 : elemGroup.Elems.Count;
            elemGroup.Elems.Insert(ind, elemInfo.Elem);

            // создание узла дерева элемента
            TreeNode elemNode = NewElemNode(elemInfo);
            TreeNode grNode = selNode.Tag is ElemInfo ? selNode.Parent : selNode;
            grNode.Nodes.Insert(ind, elemNode);
            UpdateElemNodes(grNode);
            UpdateSignals(grNode);
            treeView.SelectedNode = elemNode;
            txtElemName.Select();

            // установка признака изменения
            Modified = true;
        }