using DesktopTools.Enums; using DesktopTools.Helpers; using DesktopTools.Interfaces; using DesktopTools.Models; using ModuleTools.Attributes; using ModuleTools.BindingModels; using ModuleTools.BusinessLogics; using ModuleTools.Enums; using ModuleTools.Extensions; using ModuleTools.ViewModels; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Linq; namespace DesktopTools.Controls { public partial class GenericControlEntityList : MainControlViewEntityList, IControlViewEntityList where G : GetBindingModel, new() where S : SetBindingModel, new() where L : ListViewModel where E : ElementViewModel where BL : GenericBusinessLogic { /// /// Режим работы /// private ControlOpenMode _openMode; /// /// Событие, вызываемое при закрытии контрола /// private event Action CloseListEvent; /// /// Событие, вызываемое при закрытии контрола /// private event Action CloseSelectEvent; private readonly object _lockObject = new(); /// /// Объект бизнес-логики для получения данных /// protected BL _businessLogic; /// /// Методы для реализации в generic-контроле /// protected IGenericControlEntityList _genericControlViewEntityList; /// /// Список значений с контролов с панели поиска /// protected List<(string Name, object Value)> _searchValues; /// /// Констркутор /// public GenericControlEntityList() { InitializeComponent(); InitEvents(); _businessLogic = DependencyManager.Instance.Resolve(); _controlViewEntityList = this; } #region IControlViewEntityList public async void OpenControl(ControlOpenModel model) { _openMode = model.OpenMode; if (model.CloseList != null) { CloseListEvent += model.CloseList; } if (model.CloseSelect != null) { CloseSelectEvent += model.CloseSelect; } if (dataGridViewList.Columns.Count == 0) { try { Configurate(GetConfig()); } catch (Exception ex) { DialogHelper.MessageException(ex.Message, $"{Title}. Ошибка при конфигурации"); } } if (!model.LazyLoading) { await LoadListAsync(); } } public IControl GetInstanceControl() => _genericControlViewEntityList?.GetInstanceGenericControl(); public string GetTitleFromIdControl(Guid id) => _businessLogic.GetElement(new G { Id = id })?.ToString(); public string SaveControlToXml() => new XElement("Control", new XAttribute("Type", GetType().FullName), new XAttribute("ControlId", ControlId), new XAttribute("Title", Title), new XAttribute("AccessOperation", AccessOperation), new XElement("Configurate", new XElement("Page", toolStripTextBoxPage.Text), new XElement("CountElementsOnPage", toolStripTextBoxCountRecords.Text), new XElement("PageName", new XElement("Key", ((toolStripComboBoxPageNames.SelectedItem as PageNamesForPaginationModel)?.Key ?? "-")), new XElement("Value", ((toolStripComboBoxPageNames.SelectedItem as PageNamesForPaginationModel)?.Value ?? "-"))), new XElement("ParentId", ParentId?.ToString() ?? "-"))).ToString(); public async void LoadControlFromXml(string xml) { var control = XElement.Parse(xml); ControlId = new Guid(control.Attribute("ControlId").Value.ToString()); Title = control.Attribute("Title").Value.ToString(); AccessOperation = (AccessOperation)Enum.Parse(typeof(AccessOperation), control.Attribute("AccessOperation").Value.ToString()); var config = control.Element("Configurate"); toolStripTextBoxPage.Text = config.Element("Page").Value.ToString(); toolStripTextBoxCountRecords.Text = config.Element("CountElementsOnPage").Value.ToString(); if (config.Element("PageName").Element("Key").Value.ToString() != "-") { var pageName = new PageNamesForPaginationModel { Key = config.Element("PageName").Element("Key").Value.ToString(), Value = config.Element("PageName").Element("Value").Value.ToString() }; var elem = toolStripComboBoxPageNames.Items.Cast().FirstOrDefault(x => x.Key == pageName.Key); if (elem != null) { toolStripComboBoxPageNames.SelectedIndexChanged -= ToolStripComboBoxPageNamesSelectedIndexChanged; toolStripComboBoxPageNames.SelectedItem = elem; toolStripComboBoxPageNames.SelectedIndexChanged += ToolStripComboBoxPageNamesSelectedIndexChanged; } } if (config.Element("ParentId").Value.ToString() != "-") { ParentId = new Guid(config.Element("ParentId").Value.ToString()); } await LoadListAsync(); } #endregion /// /// Конфигуратор контрола /// /// Настройки private void Configurate(ControlViewEntityListConfiguration config) { if (config == null) { return; } // формирование таблицы на основе модели dataGridViewList.Columns.Clear(); var properties = typeof(E).GetProperties(); foreach (var property in properties) { var attr = property.GetCustomAttribute(); if (attr != null) { var colIndex = attr.DisplayName == "Идентификатор" ? 0 : dataGridViewList.Columns.Count; dataGridViewList.Columns.Insert(colIndex, new DataGridViewTextBoxColumn { HeaderText = attr.DisplayName, Name = string.Format("Column{0}", property.Name), ReadOnly = true, Visible = !attr.IsHide, Width = attr.ColumnWidth, AutoSizeMode = attr.ColumnWidth != 0 ? DataGridViewAutoSizeColumnMode.None : DataGridViewAutoSizeColumnMode.Fill }); if (attr.DefaultCellStyleFormat.IsNotEmpty()) { dataGridViewList.Columns[colIndex].DefaultCellStyle.Format = attr.DefaultCellStyleFormat; } } } labelTitle.Text = Title; // настройка отображения основных кнопок if (config.HideToolStripButton != null) { foreach (var elem in config.HideToolStripButton) { var ctrl = toolStripMenu.Items.Find(elem.ToString(), false); if (ctrl != null && ctrl.Length > 0) { ctrl[0].Visible = false; switch (elem) { case ToolStripButtonListNames.toolStripButtonAdd: toolStripSeparator1.Visible = false; break; case ToolStripButtonListNames.toolStripButtonUpd: toolStripSeparator2.Visible = false; break; case ToolStripButtonListNames.toolStripButtonDel: toolStripSeparator3.Visible = false; break; case ToolStripButtonListNames.toolStripButtonSearch: toolStripSeparator4.Visible = false; break; case ToolStripButtonListNames.toolStripButtonRef: toolStripSeparator5.Visible = false; break; } } } } // Загрузка подпунктов в контекстное меню и в пункт меню "Действие" if (config.ControlOnMoveElem != null) { foreach (var elem in config.ControlOnMoveElem) { ToolStripMenuItem item = new() { Text = elem.Value.Title, Name = elem.Key }; item.Click += elem.Value.Event; toolStripSplitButtonActions.DropDownItems.Add(item); contextMenuStripDataGrid.Items.Add(item); } } // либо скрытие пункта, если не предусмотренно подпунктов else { toolStripSplitButtonActions.Visible = false; toolStripSeparator5.Visible = false; } toolStripFooter.Visible = config.PaginationOn; // Пагинация if (config.PaginationOn) { // пагинация по страницам if (config.CountElementsOnPage.HasValue) { toolStripTextBoxCountRecords.Text = config.CountElementsOnPage.Value.ToString(); toolStripLabelPageName.Visible = toolStripComboBoxPageNames.Visible = false; } // пагинация по названиям else if (config.PageNamesForPagination != null) { toolStripButtonPrev.Visible = toolStripLabelPage.Visible = toolStripTextBoxPage.Visible = toolStripLabelCountPages.Visible = toolStripLabelCountRecords.Visible = toolStripTextBoxCountRecords.Visible = toolStripButtonNext.Visible = false; toolStripComboBoxPageNames.Items.AddRange(config.PageNamesForPagination.ToArray()); if (toolStripComboBoxPageNames.Items.Count > 0) { toolStripComboBoxPageNames.SelectedIndexChanged -= ToolStripComboBoxPageNamesSelectedIndexChanged; toolStripComboBoxPageNames.SelectedIndex = 0; toolStripComboBoxPageNames.SelectedIndexChanged += ToolStripComboBoxPageNamesSelectedIndexChanged; } toolStripComboBoxPageNames.Tag = config.ParentPropertyName; } } // при вызове контрола для выбора элемента, делаем возможность выбора только одной записи dataGridViewList.MultiSelect = _openMode == ControlOpenMode.List; // Открытие через родительский элемент if (_openMode == ControlOpenMode.Child) { panelHeader.Visible = false; toolStripButtonClose.Visible = false; toolStripFooter.Visible = false; toolStripSeparator6.Visible = true; toolStripButtonSelect.Visible = true; } Dock = DockStyle.Fill; } /// /// Инициализация событий к контролам /// private void InitEvents() { toolStripButtonAdd.Click += (object sender, EventArgs e) => { AddElement(); }; toolStripButtonUpd.Click += (object sender, EventArgs e) => { UpdElement(); }; toolStripButtonDel.Click += (object sender, EventArgs e) => { DelElement(); }; toolStripButtonSearch.Click += (object sender, EventArgs e) => { panelSearch.Visible = !panelSearch.Visible; _searchValues?.Clear(); }; toolStripButtonRef.Click += async (object sender, EventArgs e) => { await LoadListAsync(); }; toolStripButtonSelect.Click += (object sender, EventArgs e) => { SelectElement(); }; toolStripButtonClose.Click += (object sender, EventArgs e) => { CloseListEvent?.Invoke(ControlId); CloseSelectEvent?.Invoke(false); Dispose(); }; buttonSearch.Click += async (object sender, EventArgs e) => { await LoadListAsync(); }; buttonCancelSearch.Click += (object sender, EventArgs e) => { panelSearch.Visible = false; _searchValues?.Clear(); }; dataGridViewList.KeyDown += (object sender, KeyEventArgs e) => { switch (e.KeyCode) { case Keys.Insert: if (toolStripButtonAdd.Visible) { AddElement(); } break; case Keys.Enter: if (toolStripButtonUpd.Visible) { UpdElement(); } break; case Keys.Delete: if (toolStripButtonDel.Visible) { DelElement(); } break; } }; dataGridViewList.CellDoubleClick += (object sender, DataGridViewCellEventArgs e) => { if (_openMode == ControlOpenMode.Select && dataGridViewList.SelectedRows.Count > 0) { SelectElement(); } UpdElement(); }; toolStripButtonPrev.Click += async (object sender, EventArgs e) => { if (int.TryParse(toolStripTextBoxPage.Text, out int page)) { toolStripTextBoxPage.Text = (page - 1).ToString(); await LoadListAsync(); } }; toolStripButtonNext.Click += async (object sender, EventArgs e) => { if (int.TryParse(toolStripTextBoxPage.Text, out int page)) { toolStripTextBoxPage.Text = (page + 1).ToString(); await LoadListAsync(); } }; toolStripTextBoxPage.KeyDown += async (object sender, KeyEventArgs e) => { if (e.KeyData == Keys.Enter) { await LoadListAsync(); } }; toolStripComboBoxPageNames.SelectedIndexChanged += ToolStripComboBoxPageNamesSelectedIndexChanged; } /// /// Событие смены выбрарнного элемента выпдающего спика (вынесено отдельно, чтобы при настройки конфигурации не вызывать прогрузку) /// /// /// private async void ToolStripComboBoxPageNamesSelectedIndexChanged(object sender, EventArgs e) => await LoadListAsync(); /// /// Вызов события загрузки данных на datagrid /// private async Task LoadListAsync() { var cursor = Cursor.Current; var selectedGuids = new List(); foreach (DataGridViewRow row in dataGridViewList.SelectedRows) { selectedGuids.Add(new Guid(row.Cells[0].Value.ToString())); } L data = null; try { Cursor.Current = Cursors.WaitCursor; if (panelSearch.Visible) { var controls = panelSearchControls.Controls.Cast(); if (_searchValues == null) { _searchValues = new(); } _searchValues.Clear(); foreach (var cntrl in controls) { _searchValues.Add((cntrl.GetPropertyName(), cntrl.GetValueFromControl())); } } if (ParentPropertyName.IsNotEmpty()) { if (ParentId.HasValue) { await Task.Run(() => data = GetDataFromParent(ParentId.Value)); Visible = true; } else { Visible = false; } } // если включена пагинация else if (toolStripFooter.Visible) { // постраничная if (toolStripTextBoxPage.Visible) { if (int.TryParse(toolStripTextBoxPage.Text, out int page) && int.TryParse(toolStripTextBoxCountRecords.Text.ToString(), out int count)) { await Task.Run(() => data = GetDataWithPageNumber(page - 1, count)); } } // поименная else if (toolStripComboBoxPageNames.Visible) { if (toolStripComboBoxPageNames.SelectedItem is PageNamesForPaginationModel key) { await Task.Run(() => data = GetDataWithPageName(key.Key)); } } } else { await Task.Run(() => data = GetData()); } toolStripLabelCountPages.Text = $"из {data?.MaxCount}"; } catch (Exception ex) { if (_businessLogic.Errors.Count > 0) { DialogHelper.MessageException(_businessLogic.Errors, $"{Title}. Ошибки при получении данных"); } else { DialogHelper.MessageException(ex.Message, $"{Title}. Ошибка при получении данных"); } } finally { Cursor.Current = cursor; } FillDataOnGridAsync(data?.List, selectedGuids); } /// /// Заполнение таблицы /// /// private void FillDataOnGridAsync(List data, List selectedGuids) { if (data == null) { return; } dataGridViewList.Rows.Clear(); foreach (var elem in data) { var mas = new List(); foreach (DataGridViewColumn column in dataGridViewList.Columns) { mas.Add(elem.GetType().GetProperty(column.Name["Column".Length..])?.GetValue(elem)); } dataGridViewList.Rows.Add(mas.ToArray()); dataGridViewList.Rows[^1].Selected = selectedGuids.Contains(new Guid(mas[0].ToString())); } if (selectedGuids.Count == 0 && dataGridViewList.Rows.Count > 0) { dataGridViewList.Rows[0].Selected = true; } } /// /// Вызов события при добавлении элемента /// private void AddElement() => LaunchControl(null); /// /// Вызов события при изменении элемента /// private void UpdElement() { foreach (DataGridViewRow selected in dataGridViewList.SelectedRows) { LaunchControl(new Guid(selected.Cells[0].Value.ToString())); } } /// /// Вызов события при удалении элемента /// private async void DelElement() { if (MessageBox.Show("Удалить выбранные записи?", "Подтверждение", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { var cursor = Cursor.Current; try { Cursor.Current = Cursors.WaitCursor; foreach (DataGridViewRow selected in dataGridViewList.SelectedRows) { _businessLogic.Delete(new G { Id = new Guid(selected.Cells[0].Value.ToString()) }); } } catch (Exception ex) { if (_businessLogic.Errors.Count != 0) { DialogHelper.MessageException(_businessLogic.Errors, $"{Title}. Ошибки при удалении"); } else { DialogHelper.MessageException(ex.Message, $"{Title}. Ошибки при удалении"); } } finally { Cursor.Current = cursor; await LoadListAsync(); } } } /// /// Вызов события при выборе элемента /// private void SelectElement() { try { SelectedId = new Guid(dataGridViewList.SelectedRows[0].Cells[0].Value.ToString()); SelectedText = _businessLogic.GetElement(new G { Id = SelectedId })?.ToString(); CloseSelectEvent?.Invoke(true); Dispose(); } catch (Exception ex) { DialogHelper.MessageException(ex.Message, $"{Title}. Ошибка при получении выбранного значения"); } } /// /// Создание формы с контролом для работы с элементом /// /// private void LaunchControl(Guid? id) { try { var control = ControlViewEntityElement.GetInstance() as IControlChildEntity; if (ParentId.HasValue) { control.ParentId = ParentId; control.ParentPropertyName = ParentPropertyName; } if (toolStripFooter.Visible && toolStripComboBoxPageNames.Visible) { if (toolStripComboBoxPageNames.SelectedItem is PageNamesForPaginationModel key) { control.ParentId = new Guid(key.Key); control.ParentPropertyName = toolStripComboBoxPageNames.Tag?.ToString(); } } var form = new Form { Text = (id.HasValue ? $"{Title}. Редактирование" : $"{Title}. Добавление"), StartPosition = FormStartPosition.CenterScreen, ControlBox = false }; control.Open(new ControlOpenModel { OpenMode = ControlOpenMode.List, ElementId = id, CloseElement = async (Guid id) => { await LoadListAsync(); form.Close(); } }); form.Height = (control as UserControl).Height + 55; form.Width = (control as UserControl).Width + 20; form.Controls.Add(control as UserControl); form.Show(); } catch (Exception ex) { DialogHelper.MessageException(ex.Message, $"{Title}. Ошибки при открытии элемента"); } } private ControlViewEntityListConfiguration GetConfig() => _genericControlViewEntityList?.GetConfigControl(); private L GetData() => _genericControlViewEntityList?.GetDataForControl(); private L GetDataWithPageName(string key) => _genericControlViewEntityList?.GetDataWithPageNameForControl(key); private L GetDataWithPageNumber(int page, int count) => _genericControlViewEntityList?.GetDataWithPageNumberForControl(page, count); private L GetDataFromParent(Guid id) => _genericControlViewEntityList?.GetDataFromParentForControl(id); } }