Необходимо подключение библиотеки DataConnection.dll.
Шаблон кастомного DataConnection
<DataConnection Name="CustomGetDataConnection" Type="CustomGetDataConnection" Assembly="Template">
<!-- Элементы DataConnection -->
</DataConnection>
В атрибуте Type указывается имя класса, описывающего кастомный DataConnection, а в качестве значения атрибута Assembly указывается имя сборки, в которой реализован этот класс.
Для удобства и разделения логики, исходный код DataConnection можно разбить на два класса:
CustomGetDataConnectionXmlSettings - класс загрузки данных из xml-файла;
CustomGetDataConnection - класс с логикой формирования результирующей таблицы.
Парсинг xml
Полный код шаблона:
using System.Xml;
namespace WorkflowForms.DataConnections
{
public class CustomGetDataConnectionXmlSettings : GetDataConnectionXmlSettings
{
/*
* Набор свойств для хранения данных
* public string PropertyName { get; private set; }
*/
public CustomGetDataConnectionXmlSettings(IDependable parent, IWorkflowForm form, XmlNode node, XmlSqlQueryProvider queryProvider)
: base(parent, form, node)
{
/*
* Здесь должен быть парсинг xml-кода,
* чтобы получить значения тэгов и их атрибутов.
*/
}
}
}
Конструктор класса принимает параметры:
parent IDependable - ссылка на экземпляр класса CustomCommand, для которого создавался объект типа CustomCommandSettings;
form IWorkflowForm - форма, на которой описана кастомная команда;
node XmlNode - узел, который соответствует тэгу <Command>, описанному в xml-файле формы.
dataBindingProvider IDataBindingProvider -
Исполняемый код
Полный код класса:
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
namespace WorkflowForms.DataConnections
{
public class CustomGetDataConnection : GetDataConnection
{
private const string SET_PROPERTY = "SetProperty";
private const string ANY_PROPERTY = "AnyProperty";
private DataTable _table;
private IWorkflowForm _form;
protected List<Item> list = new List<Item>();
// Менеджер строковых ресурсов для поддержки языков в интерфейсе
// private Template.StringManager _manager;
#region Custom Properties
private string _anyProperty;
private string AnyProperty
{
get
{
return _anyProperty;
}
set
{
_anyProperty = value;
// Когда изменяется значение свойства объекта, необходимо сделать рассылку события всем подписчикам.
OnPropertyChange(ANY_PROPERTY);
}
}
#endregion
public CustomGetDataConnection(IWorkflowForm form, System.Xml.XmlNode node)
: base(form, node)
{
}
#region Инициализация DC
public override void InternalInit(System.Xml.XmlNode node, IWorkflowForm form)
{
base.InternalInit(node, form);
_form = form;
// _manager = new Template.StringManager(form);
LoadSettings(node, form);
// Создаем структуру результирующей таблицы
CreateTable();
}
protected void LoadSettings(System.Xml.XmlNode node, IWorkflowForm form)
{
var settings = new CustomGetDataConnectionXmlSettings(this, form, node, new XmlSqlQueryProvider());
/*
* Получение значений и сохранение в переменные
*/
}
public override async Task PostInit()
{
await Refresh();
await Task.CompletedTask;
}
#endregion
#region Основная логика
// Метод, через который элементы формы будут получать данные из DC
public override DataTable GetDataTable()
{
return _table;
}
public override async Task Refresh(string queryName = null)
{
await RefreshDataAsync();
FillTable();
// Вызов метода для рассылки события подписчикам об изменении данных в DC
OnChange();
}
private async Task RefreshDataAsync()
{
// Получение строкового ресурса по ключу
// string str = _manager.GetString("TextId");
}
#endregion
#region SetProperty
public override void SetProperty(string propertyName, Dictionary<string, object> parameters)
{
if (propertyName.Equals(SET_PROPERTY, StringComparison.OrdinalIgnoreCase))
{
// Логика обработки
}
else
{
base.SetProperty(propertyName, parameters);
}
}
#endregion
#region GetProperty
public override object GetProperty(string propertyName, Dictionary<string, object> parameters)
{
if (propertyName.Equals(ANY_PROPERTY, StringComparison.OrdinalIgnoreCase))
{
return AnyProperty;
}
else
{
return base.GetProperty(propertyName, parameters);
}
}
#endregion
#region Заполнение таблицы
private void FillTable()
{
_table.Clear();
list.ForEach(item =>
{
DataRow row = _table.NewRow();
row["FirstColumn"] = item.FirstField;
row["SecondColumn"] = item.SecondField;
row["ThirdColumn"] = item.ThirdField;
_table.Rows.Add(row);
});
}
#endregion
#region Создание таблицы
private void CreateTable()
{
// Пример создания колонок результирующей таблицы
_table = new DataTable("myTableName");
_table.Columns.Add(CreateColumn("FirstColumn", typeof(int)));
_table.Columns.Add(CreateColumn("SecondColumn", typeof(string)));
_table.Columns.Add(CreateColumn("ThirdColumn", typeof(bool)));
}
private DataColumn CreateColumn(string columnName, Type dataType, object defaultValue = null)
{
var column = new DataColumn
{
ColumnName = columnName,
DataType = dataType
};
if (defaultValue != null)
{
column.DefaultValue = defaultValue;
}
return column;
}
#endregion
}
#region Вложенные типы
public class Item
{
public int FirstField { get; set; }
public string SecondField { get; set; }
public bool ThirdField { get; set; }
}
#endregion
}
Get/Set-проперти
Кастомный GetDataConnection может иметь свои get и set-проперти, реализация которых описывается в методах GetProperty и SetProperty соответственно.
Обращение к set-проперти происходит через команду ValueSetCommand:
В конструкторе класса CustomGetDataConnectionXmlSettings необходимо прописать код вида:
// using WorkflowForms.Conditions;
// public ICondition AnyCondition { get; private set; }
string name = XmlParser.GetRequiredAttributeValue<string>(
form, node, "AnyCondition", "Name");
AnyCondition = form.GetCondition(name);
Так как имя условия указывается в качестве значения атрибута обязательного тэга, то для его получения используется статический метод GetRequiredAttributeValue класса XmlParser. В третьем параметре (string path) указываем полный путь до тэга, значение атрибута которого нужно получить. Имя атрибута указывается в четвертом параметре (string attribute). Если элемент или его атрибут отсутствует, будет возвращено исключение типа InvalidXmlException.
Если необходимо получить значение необязательного атрибута, то следует использовать метод GetAttributeValue. Этот метод в случае отсутствия элемента или его атрибута будет возвращать значение по умолчанию, переданное в параметрах метода.
Имея имя условия, объект типа ICondition можно получить через переменную form типа IWorkflowForm, используя метод GetCondition.
Исполняемая часть
В методе LoadSettings из объекта settings, переданного в метод в качестве параметра, можно получить объект типа ICondition, обратившись к публичному свойству AnyCondition:
// using WorkflowForms.Conditions;
// public ICondition _anyCondition;
_anyCondition = settings.AnyCondition;
В методе ExecuteAsyncCommand можно получать значение условия, обращаясь к свойству Value:
if (_anyCondition.Value)
{
// ...
}
SQL-запросы
Если соединение с данными должно отправлять на сервер запрос на выполнение SqlQuery, то всегда должно указываться имя процесса (WorkflowName), в рамках которого описан SQL-запрос. Аналогичный тэг указывается в описании PrimaryGetDataConnection.
Так как имя процесса и запрос являются обязательными для описания в команде, то для получения их значений используется статический метод GetRequiredAttributeValue класса XmlParser. В третьем параметре (string path) указываем полный путь до тэга, значение атрибута которого нужно получить. Имя атрибута указывается в четвертом параметре (string attribute). Если элемент или его атрибут отсутствует, будет возвращено исключение типа InvalidXmlException.
Исполняемая часть
В методе LoadSettings из объекта settings, переданного в метод в качестве параметра, можно получить имя процесса и имя SQL-запроса, который нужно выполнять:
// public string _workflowName;
// public string _anySqlQueryName;
_workflowName = settings.WorkflowName;
_anySqlQueryName = settings.AnySqlQueryName;
В методе ExecuteAsyncCommand для выполнения запроса к серверной части, необходимо из объекта формы получить клиента серверной части (WorkflowEngineClient). В метод ExecuteQuery клиента необходимо передать имя процесса, имя SQL-запроса (описанного в серверном xml-файле) и словарь параметров, значения которых должны подставляться в текст запроса:
/*
* Формирование словаря параметров, значения которых будут
* подставляться в текст запроса вместо переменных
*/
var parameters = new Dictionary<string, object>() {
// ...
};
DataTable table = await _form.WorkflowEngineClient.ExecuteQuery(
_workflowName, _anySqlQueryName, parameters
).ConfigureAwait(false);
// var arr = table.AsEnumerable().ToList().Select(row => row["title"]);
Результатом выполнения метода ExecuteQuery будет таблица типа DataTable, дальнейшая работа с которой может быть с помощью LINQ, либо путем перебора всех строк:
В конструкторе класса CustomGetDataConnectionXmlSettings необходимо прописать код вида:
// using WorkflowForms.Controls;
// public IControl AnyConrol { get; private set; }
string name = XmlParser.GetRequiredAttributeValue<string>(
form, node, "AnyControl", "Name");
AnyConrol = form.GetControl(name);
Так как имя объекта формы указывается в качестве значения атрибута обязательного тэга, то для его получения используется статический метод GetRequiredAttributeValue класса XmlParser. В третьем параметре (string path) указываем полный путь до тэга, значение атрибута которого нужно получить. Имя атрибута указывается в четвертом параметре (string attribute). Если элемент или его атрибут отсутствует, будет возвращено исключение типа InvalidXmlException.
Если необходимо получить значение необязательного атрибута, то следует использовать метод GetAttributeValue. Этот метод в случае отсутствия элемента или его атрибута будет возвращать значение по умолчанию, переданное в параметрах метода.
Имея имя объекта формы, объект типа IControl можно получить через переменную form типа IWorkflowForm, используя метод GetControl.
Исполняемая часть
В методе LoadSettings из объекта settings, переданного в метод в качестве параметра, можно получить ссылку на объект формы:
// using WorkflowForms.Controls;
// private IControl _anyConrol;
_anyConrol = settings.AnyConrol;
Для получения значения из объекта формы необходимо обращаться к свойству Value:
В конструкторе класса CustomGetDataConnectionXmlSettings необходимо прописать код вида:
// public IGetDataConnection AnyDataConnection { get; private set; }
string name = XmlParser.GetRequiredAttributeValue<string>(
form, node, "AnyDataConnection", "Name");
AnyDataConnection = form.GetDataConnection(name);
Так как имя DataConnection указывается в качестве значения атрибута обязательного тэга, то для его получения используется статический метод GetRequiredAttributeValue класса XmlParser. В третьем параметре (string path) указываем полный путь до тэга, значение атрибута которого нужно получить. Имя атрибута указывается в четвертом параметре (string attribute). Если элемент или его атрибут отсутствует, будет возвращено исключение типа InvalidXmlException.
Если необходимо получить значение необязательного атрибута, то следует использовать метод GetAttributeValue. Этот метод в случае отсутствия элемента или его атрибута будет возвращать значение по умолчанию, переданное в параметрах метода.
Имея имя соединения с данными, объект типа IGetDataConnection можно получить через переменную form типа IWorkflowForm, используя метод GetDataConnection.
Исполняемая часть
В методе LoadSettings из объекта settings, переданного в метод в качестве параметра, можно получить ссылку на DataConnection:
// using WorkflowForms.DataBindings;
// private IGetDataConnection _anyDataConnection;
_anyDataConnection = settings.AnyDataConnection;
Если кастомный DataConnection использует данные другого DataConnection, то необходимо установить зависимость первого от второго, чтобы гарантировать порядок загрузки при старте формы. Для этого в метод InternalInit класса CustomGetDataConnection необходимо добавить строки:
SetDependencies(new HashSet<IDependable>()
{
new DataConnectionDataBinding(
form, _anyDataConnection, new List<IDataBindingQuery>()),
});
Имея ссылку на DataConnection, можно получить его таблицу данных вызвав метод GetDataTable:
var dataTable = _anyDataConnection.GetDataTable();
foreach (DataRow row in dataTable.Rows)
{
// Convert.ToInt32(row["FirstField"]),
// Convert.ToString(row["SecondField"]),
// Convert.ToBoolean(row["ThirdField"])
}