<< Click to Display Table of Contents >> Navigation: Проект > Элементы дерева объектов > Палитра ФБ > Служебные > Скрипт > Руководство и примеры > Обращение к переменным проекта > Перебор переменных |
В предыдущей теме мы рассмотрели обращение к переменным, которые находятся на уровне скрипта или по произвольному имени. Однако бывают задачи когда нужно пройти по всем переменным объектам, включая вложенные и отобрать, или как то обработать, определенные переменные.
Например, сделаем пример, в котором все значения объекта в котором находится скрипт, а также вложенных записались бы в CSV файл. Подготовим набор значений
Добавим скрипт, в него добавим два входа - Записать и ПутьФайла, а также выход Ошибка.
Начнем с простого - нам необходимо чтобы код обработки переменных и записи в файл, обрабатывался по переднему фронту на входе Записать. Для этого можно применить следующую запись.
public partial class ФБ : ScriptBase
{
bool? M = false;
public override void Execute()
{
if (Записать == true && M == false)
{
}
M = Записать;
}
}
Переменная M объявлена вне метода Execute - в классе. В этом случае ее значение будет сохраняться между циклами. В условии мы проверяем, если переменная равна true и M==false, то мы вызовем код. Каждый цикл опроса M сохраняется.
Теперь разберемся с сохранением файла. Для этого можно использовать штатный функционал .Net - класс StreamWriter. Чтобы его использовать сначала нужно добавить его пространство имен:
using System.IO;
Воспользуемся перегруженным конструктором с тремя параметрами – именем файла, флагом перезаписи (false – перезапись файла, true – добавление новых данных в файл), и кодировка. При работе с неуправляемыми ресурсами - файлами, SQL соединениями и т.д. такой вызов следует обернуть в оператор using, в таком случае гарантируется очищение памяти после выполнения кода.
public partial class ФБ : ScriptBase
{
bool? M = false;
public override void Execute()
{
if (Записать == true && M == false)
{
using (var file = new StreamWriter(ПутьФайла, false, System.Text.Encoding.GetEncoding("windows-1251")))
{
}
}
M = Записать;
}
}
Теперь нужно реализовать перебор переменных в MasterSCADA, для этого можно использовать метод NavigateChilds. В данный метод передается три параметра:
1.Делегат, вызываемый для каждого дочернего элемента. Делегат - это ссылка на вызываемый метод, который вызывается для каждого дочернего элемента (item), если делегат вернет false, перебор останавливается, если true - то происходит переход к следующему элементу.
2.Тип искомых элементов - входы, значения, расчеты, команды и т.д. В нашем случае мы будет искать
3.Флаги поиска определяющие пространство поиска переменных.
Код перебора переменных будет выглядеть следующим образом.
//перебор всех значений данного объекта
HostFB.TreeItemHlp.Parent.NavigateChilds(delegate (ITreeObjectHlp item)
{
if (item.ObjectType != EObjectType.otValue)
return true;
ITreePinHlp command = (ITreePinHlp)item;
string objValue = (command.GetRTPin().ObjectValue).ToString();
file.WriteLine("{0};{1}", command.Name, objValue); //записываем в файл
return true;
}, TreeItemMask.Pin, NavigateItemsFlags.CurrentComputer);
Рассмотрим код построчно.
В первой строке происходит вызов метода NavigateChilds, где первым параметром идет наш делегат и код в виде лямбда-функции. В первой строке лямбда-функции происходит проверка на тип значения переменной:
if (item.ObjectType != EObjectType.otValue)
return true;
Это необходимо сделать, поскольку вторым параметром нашего метода мы передали TreeItemMask.Pin, а в данном параметра возвращаются и значения и входы ФБ. Поэтому необходимо сделать дополнительную проверку, чтобы не обрабатывать входы.
Далее происходит получение значения, аналогично как на прошлом шаге. После чего, с помощью метода ToString() значение преобразуется в строку.
ITreePinHlp command = (ITreePinHlp)item;
string objValue = (command.GetRTPin().ObjectValue).ToString();
После того как значение сформировано, можно записать его и имя переменной в файл.
file.WriteLine("{0};{1}", command.Name,objValue); //записываем в файл
В конце:
}, TreeItemMask.Pin, NavigateItemsFlags.CurrentComputer);
находятся два оставшихся параметра метода NavigateChilds.
TreeItemMask.Pin – определяет среди каких элементов проекта нужно выполнять поиск. Pin – это элементы тип входа - «Значение» и «Вход». Можно также задать Pout (выходы, команды), Parser (Расчет), Event (Событие), FuncBlock (функциональный блок), All (все) и другие варианты.
NavigateItemsFlags.CurrentComputer – флаги, определяющие пространство поиска переменных, в данном случае – только на текущем компьютере.
Итоговый код скрипта выглядит так:
using System;
using MasterSCADA.Script.FB;
using MasterSCADA.Hlp;
using FB;
using FB.FBAttributes;
using System.Linq;
using System.IO;
using MasterSCADALib;
[FBRetain]
public partial class ФБ : ScriptBase
{
bool? M = false;
public override void Execute()
{
if (Записать == true && M == false)
{
using (var file = new StreamWriter(ПутьФайла, false, System.Text.Encoding.GetEncoding("windows-1251")))
{
//перебор всех значений данного объекта
HostFB.TreeItemHlp.Parent.NavigateChilds(delegate (ITreeObjectHlp item)
{
if (item.ObjectType != EObjectType.otValue)
return true;
ITreePinHlp command = (ITreePinHlp)item;
string objValue = (command.GetRTPin().ObjectValue).ToString();
file.WriteLine("{0};{1}", command.Name, objValue); //записываем в файл
return true;
}, TreeItemMask.Pin, NavigateItemsFlags.CurrentComputer);
}
}
M = Записать;
}
}
Как адаптировать скрипт под свою задачу?
Сначала, нужно определится с поиском – где и переменные каких типов вы ищете. Если вы вызываете метод NavigateChilds у HostFB.TreeItemHlp.Parent, то вы выполняете поиск в объекте где находится скрипт и всех его подобъектов. Если нужно произвести поиск во всем проекте, то метод вызывается у HostFB.TreeItemHlp.Project. С помощью второго аргумента метода NavigateChilds вы определяете переменные какого типа вас интересуют (входы, выходы, расчеты или все переменные).
Затем нужно адаптировать код в лямбда-функции. Если нужно – вначале выполнить дополнительную проверку на тип возвращенной переменной, и, если она вам неинтересна, выполнить return true.
После преобразования переменной к типу ITreePinHlp, можно работать со значением, меткой времени и качеством. В нашем примере значение переменной преобразовывалось в строку. Если нужно получить конкретный тип, например, Double, то преобразование можно выполнить так:
double objValue = Convert.ToDouble(command.GetRTPin().ObjectValue);
Если нужно проверить переменную на определенный тип, то для этого нужно использовать оператор is. Например, если нас не интересуют переменные строкового типа нужно выполнить:
if (objValue is string) return true;
Теперь получив значения, вы можете оперировать с ними как вам требуется – выполнять математическую обработку, определять состояние определенных значений у переменных, экспортировать данные в СУБД и т.д.
По ссылке находится готовый проект. Проект немного дополнен - в него добавлен блок перехвата ошибок try-catch, который при обнаружении ошибок выведет сообщение в окно, а также проверяется существования папки сохранения, а в случае ее отсутствия - она создается автоматически.