Для быстрого и удобного оформления диалогов программный комплекс Топоматик Робур предлагает несколько разных классов, в том числе SimpleDlg - это стандартный класс, предназначенный для создания модальных диалогов. Он поддерживает стандартный стиль оформления, характерный для всех диалогов программного комплекса, и обладает простым и удобным функционалом.
Достаточно создать наследника от SimpleDlg и перекрыть два метода:
Достаточно часто бывает необходимо представить данные в виде редактируемой таблицы. Программный комплекс Топоматик Робур предоставляет для этого элемент управления EditTableFrame. Этот элемент предназначен для отображения таблицы со всеми необходимыми кнопками управления.
Для того чтобы заполнить таблицу данными необходимо присвоить свойство Wrapper у экземпляра EditTableFrame. Поведение и вид элемента управления элемент управления EditTableFrame зависят от реализации класса, назначенного свойству Wrapper и поддержки следующих интерфейсов:
Каждый элемент перечисления описывает строку в таблице. Заголовок таблицы строится на основании списка свойств этого элемента, используя атрибуты [DisplayName] и [Category]. Например, если элемент перечисления реализован следующим образом:
... class Item { [DisplayName("Пикет"), Category("Узлы")] public string Pk { get;set; } [DisplayName("Плюс"), Category("Узлы")] public string Plus { get;set; } [DisplayName("Отметка, м"), Category("Узлы"), DefaultDouble] public double Elevation { get;set; } } ...
Наша таблица будет выглядеть примерно так:
Отображение свойств в таблице настраивается с помощью разнообразных атрибутов, наследованных от PropertyTypeConverter, PropertyEditor и PropertyProvider. Более подробно они описаны в других разделах Руководства. В частности, для отображения перечисления в виде выпадающего списка, необходимо написать наследника от BaseEnumConverter. В котором установить соответствие между значениями перечисления и строками используя свойство Dictionary. А затем назначить его на нужное свойство используя атрибут [PropertyTypeConverter].
Создайте и настройте новый модуль для подключения к программному комплексу Топоматик Робур.
С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:
Создайте новый класс, назовите его TableWrapper.cs и разместите в нём реализацию таблицы.
//Перечисление из нескольких значений enum DataEnum { Value1, Value2, Value3 } //Структура данных, которая будет хранится в нашей модели struct DataValue { public double Length; public string TextValue; public DataEnum Value; } //Конвертер перечисления DataEnum в строковое представление и обратно class DataEnumConverter : BaseEnumConverter { public DataEnumConverter() { Dictionary[DataEnum.Value1] = "Значение1"; Dictionary[DataEnum.Value2] = "Значение2"; Dictionary[DataEnum.Value3] = "Значение3"; } } //Класс реализующий обработку содержимого таблицы //Для простоты реализации, наследуем его от SimpleChangeTrackingWrapper class TableWrapper : SimpleChangeTrackingWrapper, IActivator { //класс реализующий представление строки таблицы public class TableRow { //Указатель на нашу таблицу, необходим, чтобы при изменении свойств выставить св-во IsChanged private SimpleChangeTrackingWrapper m_Wrapper; private double m_Length; private string m_TextValue; private DataEnum m_Value; public TableRow(SimpleChangeTrackingWrapper wrapper, DataValue value) { m_Wrapper = wrapper; m_Length = value.Length; m_TextValue = value.TextValue; m_Value = value.Value; } //Свойство длина //Обратите внимание, что оно декорировано атрибутом Length - который позволяет выводить содержимое с точностью длин [DisplayName("Длина, м"), Category("Верхний заголовок|Нижний заголовок"), Length] public double Length { get { return m_Length; } set { m_Length = value; //Предупреждаем таблицу, о наличии изменений m_Wrapper.IsChanged = true; } } //Стоковое свойство [DisplayName("Строка"), Category("Верхний заголовок|Нижний заголовок")] public string TextValue { get { return m_TextValue; } set { m_TextValue = value; //Предупреждаем таблицу, о наличии изменений m_Wrapper.IsChanged = true; } } //Свойство перечисление [DisplayName("Перечисление"), Category("Верхний заголовок|Другой заголовок")] //Наш конвертер назначен с помощью атрибута PropertyTypeonverterAttribute [PropertyTypeConverter(typeof(DataEnumConverter))] public DataEnum Value { get { return m_Value; } set { m_Value = value; //Предупреждаем таблицу, о наличии изменений m_Wrapper.IsChanged = true; } } } //Сохраняем ссылку на данные модели private List<DataValue> m_Data; //При создании таблицы, заполняем её содержимое данными из модели public TableWrapper(List<DataValue> data) { m_Data = data; this.Items = new List<object>(m_Data.Count); for (int i = 0; i < m_Data.Count; i++) { this.Items.Add(new TableRow(this, m_Data[i])); } } //Считаем что наша таблица всегда доступна для редактирования public override bool IsReadOnly { get { return false; } } //При вызове метода заполняем модель по даннм нашей таблицы public override void AcceptChanges() { m_Data.Clear(); for (int i = 0; i < this.Items.Count; i++) { var row = (TableRow)this.Items[i]; m_Data.Add(new DataValue() { Length = row.Length, TextValue = row.TextValue, Value = row.Value }); } } //Реализация интерфеса IActivator //Всегда можем создавать экземпляр строки таблицы public bool CanCreateInstance { get { return true; } } //Создаем новый экземпляр строки таблицы public object CreateInstance() { return new TableRow(this, new DataValue()); } }
Теперь напишем реализацию диалога. Для этого добавьте в проект новую форму и назовите её TestSimpleDialog.
Откройте окно редактора кода, и сделайте её наследником от Topomatic.Controls.Dialogs.SimpleDlg. Затем добавьте на форму обычную панель и откройте код дизайнера в файле TestSimpleDialog.Designer.cs
Замените класс панели panel1 на EditTableFrame вручную и сохраните файл. Теперь вернитесь в окно дизайнера и разместите EditTableFrame на диалоге. После чего оформите код диалога следующим образом:
//Наследуем наш диалог от Topomatic.Controls.Dialogs.SimpleDlg partial class TestSimpleDialog : Topomatic.Controls.Dialogs.SimpleDlg { public TestSimpleDialog() { InitializeComponent(); } protected override void DoInit() { base.DoInit(); //на инициализации нам не нужно ничего делать } protected override bool DoCommit() { var wrapper = (TableWrapper)panel1.Wrapper; //при нажатии ОК проверяем, были ли изменения в таблице if (wrapper.IsChanged) //Если были, то заполняем данные модели wrapper.AcceptChanges(); return base.DoCommit(); } //Для удобства использования реализуем статический метод, который принимает данные и показывает диалог public static bool Execute(List<DataValue> values) { using (var dlg = new TestSimpleDialog()) { //из-за особенностей реализации необходимо инициализировать фрэйм до вызова ShowDialog() dlg.panel1.Wrapper = new TableWrapper(values); return dlg.ShowDialog() == DialogResult.OK; } } }
В теле программного модуля объявите команду «test_dlg_and_table», и декорируйте её атрибутом «cmd».
partial class Module : Topomatic.ApplicationPlatform.Plugins.PluginInitializator { //Используем статический список для хранения наших данных в качестве модели private static List<DataValue> m_Values = new List<DataValue>(); [cmd("test_dlg_and_table")] public void TestDlgAndTable() { //Просто вызываем метод у нашего диалога TestSimpleDialog.Execute(m_Values); } }
Задача команды «test_dlg_and_table» показать диалог редактирования данных, которые хранятся в статическом списке m_Values и дать возможность их редактировать в виде таблицы.
Теперь необходимо сформировать наш файл .plugin. Заполните его следующим образом.
{ "assemblies": { "tutorial5": { "assembly": "tutorial5.dll, tutorial5.ModulePluginHost" } }, "actions": { "id_test_dlg_and_table": { "cmd": "test_dlg_and_table", "title": "Диалог и таблица" } }, "menubars": { "rbproj": { "items": [ { "id": "test_menu", "title": "Примеры" } ] }, "rbproj.test_menu": { "items": [ "id_test_dlg_and_table" ] } } }
Здесь мы описываем actions для нашей команды, и добавляем пункт в меню. Результатом запуска проекта будет появления в главном меню пункта «Примеры», с подпунктом «Диалог и таблица», который будет работать в соответствии с описанным выше алгоритмом. После запуска и выполнения мы увидим следующий результат: