Здесь показаны различия между двумя версиями данной страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
developers:tutorial:dlgandpropertygrid [2019/02/10 18:36] vasya |
developers:tutorial:dlgandpropertygrid [2022/03/15 19:13] (текущий) proxor |
||
---|---|---|---|
Строка 54: | Строка 54: | ||
Отображение свойств в таблице настраивается с помощью разнообразных атрибутов, наследованных от [[developers:references:topomatic.componentmodel.propertytypeconverter|PropertyTypeConverter]], [[developers:references:topomatic.componentmodel.propertyeditor|PropertyEditor]] и [[developers:references:topomatic.componentmodel.propertyprovider|PropertyProvider]]. Более подробно они описаны в других разделах [[developers:tutorial:start|Руководства]]. | Отображение свойств в таблице настраивается с помощью разнообразных атрибутов, наследованных от [[developers:references:topomatic.componentmodel.propertytypeconverter|PropertyTypeConverter]], [[developers:references:topomatic.componentmodel.propertyeditor|PropertyEditor]] и [[developers:references:topomatic.componentmodel.propertyprovider|PropertyProvider]]. Более подробно они описаны в других разделах [[developers:tutorial:start|Руководства]]. | ||
- | Например, для отображения перечисления в виде выпадающего списка, необходимо написать наследника от [[developers:references:topomatic.componentmodel.baseenumconverter|BaseEnumConverter]]. В котором установить соответствие между значениями перечисления и строками используя свойство **Dictionary**. А затем назначить его на нужное свойство используя атрибут [[developers:references:topomatic.componentmodel.propertytypeconverterattribute|[PropertyTypeConverter]]]. | + | В частности, для отображения перечисления в виде выпадающего списка, необходимо написать наследника от [[developers:references:topomatic.componentmodel.baseenumconverter|BaseEnumConverter]]. В котором установить соответствие между значениями перечисления и строками используя свойство **Dictionary**. А затем назначить его на нужное свойство используя атрибут [[developers:references:topomatic.componentmodel.propertytypeconverterattribute|[PropertyTypeConverter]]]. |
Создайте и настройте новый [[developers:tutorial:module|модуль]] для подключения к программному комплексу [[http://www.topomatic.ru|Топоматик Робур]]. | Создайте и настройте новый [[developers:tutorial:module|модуль]] для подключения к программному комплексу [[http://www.topomatic.ru|Топоматик Робур]]. | ||
Строка 70: | Строка 70: | ||
Создайте новый класс, назовите его TableWrapper.cs и разместите в нём реализацию таблицы. | Создайте новый класс, назовите его TableWrapper.cs и разместите в нём реализацию таблицы. | ||
<code csharp> | <code csharp> | ||
+ | //Перечисление из нескольких значений | ||
+ | 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()); | ||
+ | } | ||
+ | } | ||
</code> | </code> | ||
+ | |||
+ | <note>Обратите внимание, что свойство **Length** в строке таблицы декорировано атрибутом [[developers:references:topomatic.cad.foundation.design.lengthattribute|Length]]. Большая часть атрибутов реализованных в сборках программного комплекса, реализованы в пространствах имен **Design**</note> | ||
+ | |||
+ | Теперь напишем реализацию диалога. Для этого добавьте в проект новую форму и назовите её TestSimpleDialog. | ||
+ | |||
+ | {{ :developers:tutorial:dlgandpropertygrid:create_form.png?direct&600 |}} | ||
+ | |||
+ | Откройте окно редактора кода, и сделайте её наследником от [[developers:references:topomatic.controls.dialogs.simpledlg|Topomatic.Controls.Dialogs.SimpleDlg]]. Затем добавьте на форму обычную панель и откройте код дизайнера в файле TestSimpleDialog.Designer.cs | ||
+ | |||
+ | {{ :developers:tutorial:dlgandpropertygrid:add_panel.png?direct&600 |}} | ||
+ | |||
+ | Замените класс панели **panel1** на [[developers:references:topomatic.controls.dialogs.edittableframe|EditTableFrame]] вручную и сохраните файл. | ||
+ | Теперь вернитесь в окно дизайнера и разместите [[developers:references:topomatic.controls.dialogs.edittableframe|EditTableFrame]] на диалоге. После чего оформите код диалога следующим образом: | ||
+ | <code csharp> | ||
+ | //Наследуем наш диалог от 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; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | В теле программного модуля объявите команду "test_dlg_and_table", и декорируйте её атрибутом "cmd". | ||
+ | <code csharp> | ||
+ | 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); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Задача команды "test_dlg_and_table" показать диалог редактирования данных, которые хранятся в статическом списке **m_Values** и дать возможность их редактировать в виде таблицы. | ||
+ | |||
+ | Теперь необходимо сформировать наш файл .plugin. Заполните его следующим образом. | ||
+ | <code javascript> | ||
+ | { | ||
+ | "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" | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Здесь мы описываем [[developers:references:core.plugin:actions|actions]] для нашей команды, и добавляем пункт в меню. | ||
+ | Результатом запуска проекта будет появления в главном меню пункта «Примеры», с подпунктом "Диалог и таблица", который будет работать в соответствии с описанным выше алгоритмом. После запуска и выполнения мы увидим следующий результат: | ||
+ | |||
+ | {{ :developers:tutorial:dlgandpropertygrid:result.png?direct&600 |}} | ||
+ | |||
+ | <note>[[developers:tutorial:tutorialcode|Исходный код]] примера расположен в проекте **"tutorial5"**.</note> |