ФБ "Скрипт C#" и его использование в MasterSCADA. Управление трендом

ФБ "Скрипт C#" и его использование в MasterSCADA. Управление трендом

В данном примере мы рассмотрим, как управлять параметрами тренда в режиме исполнения.

Иногда возникает необходимость управлять какими-либо параметрами тренда или журнала. В качестве примера мы рассмотрим управление видимостью перьев на тренде.
Прежде чем изменять или обращаться к каким-либо параметрами тренда нужно сначала получить его класс. Принцип получения класса и журнала, и тренда полностью идентичен, но способ получения класса отличается в зависимости от того находится тренд/журнал на мнемосхеме или сделан как отдельный документ.
В качестве примера сделаем скрипт, который будет управлять видимостью трех перьев тренда расположенного на мнемосхеме.
Сначала сделаем необходимую заготовку проекта – создадим три значения с имитацией (их мы добавим на тренд), три команды видимости перьев (ими мы будем управлять видимостью), команду Применить и скрипт, с 4 входами – состоянием видимости и Применить. На мнемосхему добавим тренд и элементы управления видимостью.
Теперь приступим к написаю скрипта.
Видимость перьев будет применять только после нажатия оператором кнопки Применить. Сделаем чтобы код вызывался по переднему фронту:
public partial class ФБ : ScriptBase
{    
    bool? M=false;
     
    public override void Execute()
    {
    if (Применить==true && M==false) 
    {
         
         
    }
    M=Применить;        
    }
}


Скрипт будет обращаться к тренду, расположенному на мнемосхеме объекта в котором он расположен. При этом на одной мнемосхеме может быть расположено несколько трендов, кроме того возможна ситуация, когда открыты разные окна (например, мнемосхема и окно объекта), каждое из которых будет иметь по тренду. Поэтому мы добавим две константы – с именем тренда, и названием документа на котором он расположен. Также добавим переменную хранящую текущий объект, а также переменную для всего проекта – она нам понадобится для поиска тренда.
const string ИМЯ_ТРЕНДА = "Тренд";    
const string ИМЯ_ОКНА = "Мнемосхема";    
bool? M=false;    
public override void Execute()    { 
//Ссылка на текущий проект        
var проект = HostFB.TreeItemHlp.Project;        
//получаем корневой объект
var объект = (ITreeItemHlp)HostFB.TreeItemHlp.Parent;   


Теперь обратимся к тренду. В MasterSCADA все тренды реализованы в виде отдельных потоков, поэтому обратится к тренду расположенному на определенной мнемосхеме нельзя – нужно найти его среди открытых трендов, и уже после этого работать с ним. Поскольку мы будем обращаться к другим потокам, то код выполняющий данную операцию должен быть заключен в метод BeginInvoke:

https://msdn.microsoft.com/ru-ru/library/0b1bf3y3(v=vs.110).aspx

Код будет выглядеть следующим образом:
//получаем тренд         
RTManager.Instance.ThreadHolder.BeginInvoke(new ThreadStart(delegate
{
//здесь разместим код для работы с трендом
}));



Для того чтобы метод BeginInvoke был доступен, нужно в секции using подключить сборку using MasterSCADA.RT.
Теперь приступим к перебору всех открытых трендов:
//получаем тренд         
         RTManager.Instance.ThreadHolder.BeginInvoke(new ThreadStart(delegate
         {
  //перебираем открытые тренды
            foreach (Trend trend in проект.GetService<TrendService>().Opened)
            {            
            var host = trend.Host as System.Windows.Forms.Control;
            if (host!=null)
             {
             Object name = WinFormsControlBase.GetAmbientProperty(host, WindowlessControlBase.DISPID.DISPID_AMBIENT_NAME);
             if (name.ToString()!=ИМЯ_ТРЕНДА || trend.Attribute.TreeItem.ID!=объект.ID || trend.Attribute.DisplayName!=ИМЯ_ОКНА) continue;  
             
                         
             }
        }     
        }));


С помощью цикла foreach, мы перебираем все открытые тренды. Каждый тренд полученный в цикле (переменная trend), мы с помощью оператора as проверяем и приводим полученный элемент к типу System.Windows.Forms.Control, после чего проверяем его на null – таким образом мы должны убедится, что действительно обратились к контролу. Затем мы определяем имя полученного контрола.
Теперь проверим что мы получили именно тот тренд, который нам нужен – мы проверим совпадает ли имя с прописанной в константе ИМЯ_ТРЕНДА, убедимся, что ID объекта мнемосхемы, на котором расположен тренд, равен ID объекта в который вставлен скрипт, и что название документа, на котором расположен тренд, равен константе ИМЯ_ОКНА. В противном случае мы переходим к следующему контролу с помощью оператор continue.

После этого начинать работать с переменной trend – обращаться к его свойствам. В данном случае нам нужно получить коллекцию перьев, а затем поочередно задать видимость каждого пера, согласно значению на входе.
//получаем коллекцию перьев
            var list = trend.Settings.Objects.OfType<MasterSCADA.Graph.Objects.Graph2D>().ToList();                    
            //далее поиск по номеру
             //получаем нулевое перо
            var param=list[0];            
            //скрыть видимость параметра тренда
            param.Visible=Видимость_пера_0.Value;                
            //получаем первое перо
            param=list[1];            
            //скрыть видимость параметра тренда
            param.Visible=Видимость_пера_1.Value;               
            //получаем второе перо
            param=list[2];            
            //скрыть видимость параметра тренда
            param.Visible=Видимость_пера_2.Value;



Скрипт готов. Итоговый код выглядит так:
public partial class ФБ : ScriptBase
{
    const string ИМЯ_ТРЕНДА = "Тренд";    
    const string ИМЯ_ОКНА = "Мнемосхема";    
    bool? M=false;    
    public override void Execute()
    {
    if (Применить==true && M==false) 
    { 
        //Ссылка на текущий проект        
        var проект = HostFB.TreeItemHlp.Project;        
        //получаем корневой объект
        var объект = (ITreeItemHlp)HostFB.TreeItemHlp.Parent;        
        //получаем тренд         
         RTManager.Instance.ThreadHolder.BeginInvoke(new ThreadStart(delegate
         {
            foreach (Trend trend in проект.GetService<TrendService>().Opened)
            {            
            var host = trend.Host as System.Windows.Forms.Control;            
            if (host!=null)
             {
             Object name = WinFormsControlBase.GetAmbientProperty(host, WindowlessControlBase.DISPID.DISPID_AMBIENT_NAME);
             if (name.ToString()!=ИМЯ_ТРЕНДА || trend.Attribute.TreeItem.ID!=объект.ID || trend.Attribute.DisplayName!=ИМЯ_ОКНА) continue;  
            //получаем коллекцию перьев
            var list = trend.Settings.Objects.OfType<MasterSCADA.Graph.Objects.Graph2D>().ToList();                    
            //далее поиск по номеру
             //получаем нулевое перо
            var param=list[0];            
            //скрыть видимость параметра тренда
            param.Visible=Видимость_пера_0.Value;                
            //получаем первое перо
            param=list[1];            
            //скрыть видимость параметра тренда
            param.Visible=Видимость_пера_1.Value;               
            //получаем второе перо
            param=list[2];            
            //скрыть видимость параметра тренда
            param.Visible=Видимость_пера_2.Value;                            
             }
        }     
        }));         
    }
    M=Применить;        
    }
}



Проверим работу скрипта – запустим режим исполнения и попробуем скрыть какое-либо перо.
Пример данного скрипта можно скачать по ссылке.
Если необходимо менять настройки закрытых трендов или в режиме разработки, то в этом случае применяются другие методы – загружается файл настроек тренда и выполняются изменения.
В качестве примера мы будем менять путь к папке снимков (папка по умолчанию куда происходит сохранение экспортируемых в графические форматы графиков) у тренда «Тренд» текущего объекта.

Сначала обратимся к текущему объекту и переберем все его тренды. Если имя тренда не равно, то выйдем из цикла.
var объект=HostFB.TreeItemHlp.Parent;                   
IAttributesHlp trends = объект.Attributes;         
foreach (IAttributeHlp trend in trends)
{       
 if (trend.Attribute.DisplayName!= "Тренд") continue;
  
       
} 


Теперь откроем настройки тренда и выполним изменение настройки «Папка снимков».
var объект=HostFB.TreeItemHlp.Parent;                   
IAttributesHlp trends = объект.Attributes;         
foreach (IAttributeHlp trend in trends)
{       
 if (trend.Attribute.DisplayName!= "Тренд") continue;
 using (var changer = new TrendSettingsChanger())
 {
  //загрузка настроек    
  var настройки = changer.Load(trend.DocFile);
  //изменение настроек
  string ИМЯ_НАСТРОЙКИ_ТРЕНДА = "Папка снимков";
  string ЗНАЧЕНИЕ_НАСТРОЙКИ_ТРЕНДА= @"D:\Тренды";           if (trend.Opened==false)        
  {
   var результат = настройки.SetProperty(trend, ИМЯ_НАСТРОЙКИ_ТРЕНДА, ЗНАЧЕНИЕ_НАСТРОЙКИ_ТРЕНДА);    
  }
 }       
}


Больше ничего не требуется.
Проверка на состояние открытия тренда требуется из-за того, что данный метод работает только для закрытых трендов. У открытых трендов настройки меняются по методу, описанному выше. Поэтому если требуется менять параметры трендов в режиме исполнения, то нужно комбинировать оба метода – сначала менять настройки всех открытых трендов, а затем закрытых.

По ссылке можно скачать пример такого скрипта, в котором происходит изменение настроек всех трендов проекта (как закрытых, так и открытых).