Example #1
0
        // Показ формы с полями для класса параметра
        public static Form ShowPropertyFormDialog(object userModel, object userClass,
                                                  string fontName = "Microsoft Sans Serif", float fontSize = 8.25f)
        {
            // заготовка для формы диалога
            var frm = new Form()
            {
                Text            = GetClassCaption(userClass),
                AutoSize        = true,                           // размер подстраивается под содержимое
                AutoSizeMode    = AutoSizeMode.GrowAndShrink,     // автоматически увеличивает или уменьшает размер
                StartPosition   = FormStartPosition.CenterParent, // показывает форму по центру родительского окна
                FormBorderStyle = FormBorderStyle.FixedDialog,    // формат рамки формы
                MaximizeBox     = false,                          // не показывать кнопку "Развернуть"
                MinimizeBox     = false,                          // не показывать кнопку "Свернуть"
                ShowInTaskbar   = false                           // не показывать в панели задач
            };

            frm.Font = new Font(fontName, fontSize);

            // создаём заготовку панели свойств
            var ppb = new PropertyPanelBuilder(frm);

            // размещаем панель на форме
            frm.Controls.Add(ppb.BuildPropertyPanel(userModel, userClass));

            // показываем форму диалога
            frm.ShowDialog();

            // возвращаем ссылку на объект формы
            return(frm);
        }
Example #2
0
        /// <summary>
        /// Построение панели с таблицей
        /// </summary>
        /// <param name="userModel">Корневой класс модели</param>
        /// <param name="userClass">Класс сущности</param>
        /// <param name="userCollection">Коллекция сущностей</param>
        /// <param name="userFilteredCollection">Коллекция сущностей фильтрованная</param>
        /// <param name="propertyNames">Имя свойства для фильтра</param>
        /// <param name="propertyValues">Значение свойства для фильтра</param>
        /// <returns></returns>
        public static GridPanel BuildPropertyPanel(object userModel, object userClass, object userCollection,
                                                   object userFilteredCollection = null, string[] propertyNames = null, Guid[] propertyValues = null)
        {
            // заготовка для таблицы записей
            var userControl = new GridPanel
            {
                Dock = DockStyle.Fill
            };
            // создаём сетку для компоновки
            var grid = new TableLayoutPanel()
            {
                Dock        = DockStyle.Fill,
                ColumnCount = 1,
                RowCount    = 2
            };

            grid.ColumnStyles.Add(new ColumnStyle());
            grid.RowStyles.Add(new RowStyle());
            grid.RowStyles.Add(new RowStyle()
            {
                SizeType = SizeType.Percent, Height = 100
            });
            // кнопка "Добавить"
            var btnAdd = new Button
            {
                Text     = "Добавить",
                Anchor   = AnchorStyles.Left,
                AutoSize = true
            };
            // заготовка для таблицы
            var listView = new ListView
            {
                Name             = "listView",
                Dock             = DockStyle.Fill,
                MultiSelect      = false,
                FullRowSelect    = true,
                HideSelection    = false,
                ShowItemToolTips = true,
                VirtualMode      = true,
                GridLines        = true,
                View             = View.Details
            };
            var btnEdit = new Button
            {
                Text     = "Изменить",
                Anchor   = AnchorStyles.Left,
                AutoSize = true,
                Enabled  = false
            };
            var btnDelete = new Button
            {
                Text     = "Удалить",
                Anchor   = AnchorStyles.Left,
                AutoSize = true,
                Enabled  = false
            };

            // обработчик действия при нажатии кнопки "Добавить"
            btnAdd.Click += (o, e) =>
            {
                // создаём пустой объект требуемого типа
                var item = Activator.CreateInstance(userClass.GetType());

                // задаём значение фильтрованного свойства из propertyName и propertyValue
                if (userFilteredCollection != null && propertyNames != null && propertyValues != null &&
                    propertyNames.Length == propertyValues.Length)
                {
                    for (var i = 0; i < propertyNames.Length; i++)
                    {
                        if (!string.IsNullOrWhiteSpace(propertyNames[i]) && propertyValues[i] != Guid.Empty)
                        {
                            PropertyInfo piInstance = item.GetType().GetProperty(propertyNames[i]);
                            piInstance.SetValue(item, propertyValues[i]);
                        }
                    }
                }

                // вызываем диалог для заполнения свойств объекта
                var frm = PropertyPanelBuilder.ShowPropertyFormDialog(userModel, item, userControl.Font.Name, userControl.Font.Size);
                // если не была нажата клавиша "Ввод", выходим
                if (frm.DialogResult != DialogResult.OK)
                {
                    return;
                }

                // формируем данные для вызова метода Add коллекции объектов:
                // заказываем типы параметров для вызова метода
                Type[] parameterTypes = { item.GetType() };
                // создаём ссылку на метод Add, с формальным списком параметров
                MethodInfo method = userCollection.GetType().GetMethod("Add", parameterTypes);
                // формируем массив значений параметров для передачи при вызове метода
                object[] arguments = { item };
                try
                {
                    // вызываем метод на коллекции объектов с аргументами
                    method.Invoke(userCollection, arguments);
                    if (userFilteredCollection != null)
                    {
                        method = userFilteredCollection.GetType().GetMethod("Add", parameterTypes);
                        method.Invoke(userFilteredCollection, arguments);
                    }
                }
                catch (Exception ex)
                {
                    OnError(ex.InnerException != null
                        ? ex.InnerException.Message
                        : ex.Message, "Добавление записи");
                }
                listView.VirtualListSize = 0;                                                                                                          // сбросим виртуальный размер
                listView.VirtualListSize = ((IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection)).Count(); // установим размер по размеру коллекции
                listView.Invalidate();                                                                                                                 // просим обновить вид
                btnEdit.Enabled = btnDelete.Enabled = false;
                userControl.OnGridSelectedChanged(item);
                // ищем новую строку в списке
                var lvi = listView.FindItemWithText(item.ToString());
                if (lvi != null) // если найдена, то делаем ее текущей
                {
                    lvi.Selected = true;
                    lvi.EnsureVisible();
                }
            };
            btnEdit.Click += (o, e) =>
            {
                if (listView.SelectedIndices.Count == 0)
                {
                    return;
                }
                // получаем ссылку на коллекцию
                var collection = (IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection);
                // получаем ссылку на редактируемый элемент
                var oldItem = collection.ElementAt(listView.SelectedIndices[0]);
                // сохраняем старую версию объекта
                var item = oldItem.DeepClone();
                // вызываем диалог для заполнения свойств объекта
                var frm = PropertyPanelBuilder.ShowPropertyFormDialog(userModel, item, userControl.Font.Name, userControl.Font.Size);
                // если не была нажата клавиша "Ввод", выходим
                if (frm.DialogResult != DialogResult.OK)
                {
                    return;
                }

                // формируем данные для вызова метода Add коллекции объектов:
                // заказываем типы параметров для вызова метода
                Type[] parameterTypes = { oldItem.GetType(), item.GetType() };
                // создаём ссылку на метод Add, с формальным списком параметров
                MethodInfo method = userCollection.GetType().GetMethod("ChangeTo", parameterTypes);
                // формируем массив значений параметров для передачи при вызове метода
                object[] arguments = { oldItem, item };
                try
                {
                    // вызываем метод на коллекции объектов с аргументами
                    method.Invoke(userCollection, arguments);
                }
                catch (Exception ex)
                {
                    OnError(ex.InnerException != null
                        ? ex.InnerException.Message
                        : ex.Message, "Изменение записи");
                }
                listView.VirtualListSize = 0;                                                                                                          // сбросим виртуальный размер
                listView.VirtualListSize = ((IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection)).Count(); // установим размер по размеру коллекции
                listView.Invalidate();                                                                                                                 // просим обновить вид
                btnEdit.Enabled = btnDelete.Enabled = false;
                userControl.OnGridSelectedChanged(item);
                // ищем новую строку в списке
                var lvi = listView.FindItemWithText(item.ToString());
                if (lvi != null) // если найдена, то делаем ее текущей
                {
                    lvi.Selected = true;
                    lvi.EnsureVisible();
                }
            };
            btnDelete.Click += (o, e) =>
            {
                if (listView.SelectedIndices.Count == 0)
                {
                    return;
                }
                if (MessageBox.Show("Удалить текущую строку?", "Удаление строки",
                                    MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
                                    MessageBoxDefaultButton.Button2) != DialogResult.Yes)
                {
                    return;
                }
                // получаем ссылку на коллекцию
                var collection = (IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection);
                // получаем ссылку на редактируемый элемент
                var item = collection.ElementAt(listView.SelectedIndices[0]);
                // формируем данные для вызова метода Add коллекции объектов:
                // заказываем типы параметров для вызова метода
                Type[] parameterTypes = { item.GetType() };
                // создаём ссылку на метод Remove, с формальным списком параметров
                MethodInfo method = userCollection.GetType().GetMethod("Remove", parameterTypes);
                // формируем массив значений параметров для передачи при вызове метода
                object[] arguments = { item };
                try
                {
                    // вызываем метод на коллекции объектов с аргументами
                    method.Invoke(userCollection, arguments);
                    if (userFilteredCollection != null)
                    {
                        method = userFilteredCollection.GetType().GetMethod("Remove", parameterTypes);
                        method.Invoke(userFilteredCollection, arguments);
                    }
                }
                catch (Exception ex)
                {
                    OnError(ex.InnerException != null
                        ? ex.InnerException.Message
                        : ex.Message, "Удаление записи");
                }
                listView.VirtualListSize = 0;                                                                                                          // сбросим виртуальный размер
                listView.VirtualListSize = ((IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection)).Count(); // установим размер по размеру коллекции
                listView.Invalidate();                                                                                                                 // просим обновить вид
                btnEdit.Enabled = btnDelete.Enabled = false;
                userControl.OnGridSelectedChanged(null);
            };
            // создадим панель для размещения кнопок
            var flow = new FlowLayoutPanel
            {
                Name         = "buttonsPanel",
                AutoSize     = true,
                AutoSizeMode = AutoSizeMode.GrowAndShrink,
                Dock         = DockStyle.Left
            };

            // добавим кнопки в панель кнопок
            flow.Controls.Add(btnAdd);
            flow.Controls.Add(btnEdit);
            flow.Controls.Add(btnDelete);
            // добавим панель кнопок в сетку
            grid.Controls.Add(flow, 0, 0);
            var gr      = listView.CreateGraphics();
            var colsmax = new List <float>();
            // получаем тип объекта, переданного через параметр
            var type = userClass.GetType();

            MemberInfo[] m     = type.GetProperties(); // получаем массив свойств объекта
            var          count = 0;

            foreach (var info in m) // для каждого свойства из массива свойств
            {
                // получаем ссылку на свойство по его имени
                var prop = type.GetProperty(info.Name);
                // если столбец не показывается в таблице, пропускаем
                if (!PropertyPanelBuilder.CheckTableBrowsabeMode(userClass, prop))
                {
                    continue;
                }
                // получаем наименование свойства из дескриптора
                var caption   = PropertyPanelBuilder.GetPropertyCaption(userClass, prop);
                var text      = string.IsNullOrWhiteSpace(caption) ? prop.Name : caption;
                var width     = gr.MeasureString(text, listView.Font).Width + 16;
                var typeName  = prop.PropertyType.ToString();
                var textAlign = HorizontalAlignment.Left;
                switch (typeName)
                {
                case "System.Guid":
                    if (count++ == 0)
                    {
                        continue;
                    }
                    colsmax.Add(width);
                    break;

                case "System.String":
                    if (PropertyPanelBuilder.CheckPasswordMode(userClass, prop))
                    {
                        continue;
                    }
                    colsmax.Add(width);
                    break;

                case "System.Int32":       // для целочисленных свойств
                case "System.Single":      // для свойств натуральных чисел
                case "System.Decimal":     // для свойств с ценой
                    textAlign = HorizontalAlignment.Right;
                    colsmax.Add(width);
                    break;

                case "System.DateTime":     // для свойств с датой
                    textAlign = HorizontalAlignment.Center;
                    colsmax.Add(width);
                    break;

                case "System.Boolean":     // для логических свойств
                    textAlign = HorizontalAlignment.Center;
                    colsmax.Add(width);
                    break;

                default:
                    if (prop.PropertyType.BaseType.FullName == "System.Enum")
                    {
                        textAlign = HorizontalAlignment.Center;
                        colsmax.Add(width);
                        break;
                    }
                    continue;
                }
                listView.Columns.Add(new ColumnHeader
                {
                    Text      = text,
                    TextAlign = textAlign,
                    Width     = (int)width
                });
            }
            // цепляем обработчик для виртуального режима
            listView.RetrieveVirtualItem += (o, e) =>
            {
                var lv = (ListView)o;
                e.Item = new ListViewItem();
                // получаем ссылку на коллекцию
                var collection = (IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection);
                if (e.ItemIndex >= collection.Count())
                {
                    for (var i = 1; i < lv.Columns.Count; i++)
                    {
                        e.Item.SubItems.Add("");
                    }
                    return;
                }
                // получаем ссылку на рисуемый элемент
                var item = collection.ElementAt(e.ItemIndex);
                // получаем его тип
                type  = item.GetType();
                m     = type.GetProperties();      // получаем массив свойств объекта
                count = 0;                         // счетчик столбцов
                for (var i = 0; i < m.Length; i++) // для каждого свойства из массива свойств
                {
                    // получаем ссылку на свойство по его имени
                    var prop = type.GetProperty(m[i].Name);
                    // если столбец не показывается в таблице, пропускаем
                    if (!PropertyPanelBuilder.CheckTableBrowsabeMode(userClass, prop))
                    {
                        continue;
                    }
                    // если свойство первое и его тип Guid (ключевой столбец) - пропускаем
                    if (i == 0 && prop.PropertyType == typeof(Guid))
                    {
                        continue;
                    }
                    string value; // здесь будет значение
                    if (prop.PropertyType == typeof(DateTime))
                    {
                        value = ((DateTime)prop.GetValue(item)).ToShortDateString();
                    }
                    else if (prop.PropertyType == typeof(bool))
                    {
                        value = ((bool)prop.GetValue(item)) ? "Да" : "Нет";
                    }
                    else if (prop.PropertyType == typeof(decimal))
                    {
                        value = ((decimal)prop.GetValue(item)).ToString("0.00");
                    }
                    else if (prop.PropertyType == typeof(Single))
                    {
                        value = ((Single)prop.GetValue(item)).ToString("0.0");
                    }
                    else if (prop.PropertyType == typeof(int))
                    {
                        value = ((int)prop.GetValue(item)).ToString("0");
                    }
                    else if (prop.PropertyType == typeof(string))
                    {
                        if (PropertyPanelBuilder.CheckPasswordMode(userClass, prop))
                        {
                            continue;
                        }
                        value = prop.GetValue(item)?.ToString();
                    }
                    else if (prop.PropertyType == typeof(Guid))
                    {
                        value = GetLookupName(prop, item, userModel);
                    }
                    else if (prop.PropertyType.BaseType == typeof(Enum))
                    {
                        value = GetEnumName(prop, item, userModel);
                    }
                    else
                    {
                        continue;
                    }
                    var width = gr.MeasureString(value, lv.Font).Width + 16;
                    // делаем столбец шире, если нужно
                    if (count < lv.Columns.Count && lv.Columns[count].Width < (int)width)
                    {
                        lv.Columns[count].Width = (int)width;
                    }
                    // если не было столбцов, пишем в первый
                    if (count++ == 0)
                    {
                        e.Item.Text = value;
                    }
                    else // иначе добавляем
                    {
                        e.Item.SubItems.Add(value);
                    }
                }
            };
            // цепляем обработчик для виртуального поиска
            listView.SearchForVirtualItem += (o, e) =>
            {
                // e.Text содержит строковое представление объекта (перегрузкой метода ToString())
                // получаем ссылку на коллекцию
                var collection = (IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection);
                var n          = 0;
                foreach (var item in collection)
                {
                    if (item.ToString().StartsWith(e.Text, true,
                                                   System.Globalization.CultureInfo.GetCultureInfo("Ru-ru")))
                    {
                        e.Index = n;
                        break;
                    }
                    n++;
                }
            };
            // указываем размер коллекции
            listView.VirtualListSize = ((IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection)).Count();
            // разрешаем кнопки редактирования
            listView.SelectedIndexChanged += (o, e) =>
            {
                var lv = (ListView)o;
                btnEdit.Enabled = btnDelete.Enabled = lv.SelectedIndices.Count > 0;
                if (lv.SelectedIndices.Count > 0)
                {
                    var collection = (IEnumerable <object>)(userFilteredCollection != null ? userFilteredCollection : userCollection);
                    var item       = collection.ElementAt(lv.SelectedIndices[0]);
                    userControl.OnGridSelectedChanged(item);
                }
                else
                {
                    userControl.OnGridSelectedChanged(null);
                }
            };

            // добавим детальный список в сетку
            grid.Controls.Add(listView, 0, 1);
            // добавим сетку на панель свойств
            userControl.Controls.Add(grid);
            // возвращаем сформированный контрол
            return(userControl);
        }