414 lines
17 KiB
C#
414 lines
17 KiB
C#
using System;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Windows.Forms;
|
||
using System.Xml.Linq;
|
||
using ToolsDesktop.BaseControls;
|
||
using ToolsDesktop.Enums;
|
||
using ToolsDesktop.Helpers;
|
||
using ToolsDesktop.Interfaces;
|
||
using ToolsDesktop.Models;
|
||
using ToolsModule.Attributes;
|
||
using ToolsModule.BindingModels;
|
||
using ToolsModule.BusinessLogics;
|
||
using ToolsModule.Enums;
|
||
using ToolsModule.Extensions;
|
||
using ToolsModule.Interfaces;
|
||
using ToolsModule.ViewModels;
|
||
|
||
namespace ToolsDesktop.Controls
|
||
{
|
||
public partial class GenericControlEntityElement<G, S, L, E, BL> : MainControlViewEntityElement, IControlViewEntityElement
|
||
where G : GetBindingModel, new()
|
||
where S : SetBindingModel, new()
|
||
where L : ListViewModel<E>
|
||
where E : ElementViewModel
|
||
where BL : IGenericEntityLogic<G, S, L, E>
|
||
{
|
||
/// <summary>
|
||
/// Объект бизнес-логики для получения данных
|
||
/// </summary>
|
||
protected readonly BL _businessLogic;
|
||
|
||
/// <summary>
|
||
/// Методы для реализации в generic-контроле
|
||
/// </summary>
|
||
protected IGenericControlEntityElement _genericControlViewEntityElement;
|
||
|
||
/// <summary>
|
||
/// Признак налиичия изменений
|
||
/// </summary>
|
||
private bool _haveChages = false;
|
||
|
||
/// <summary>
|
||
/// Ширина контрола по умолчанию
|
||
/// </summary>
|
||
private readonly int _defaultControlWidth = 350;
|
||
|
||
protected E _element = null;
|
||
|
||
/// <summary>
|
||
/// Событие, вызываемое при закрытии контрола
|
||
/// </summary>
|
||
private event Action<Guid> CloseElementEvent;
|
||
|
||
/// <summary>
|
||
/// События установки одинаковой ширины для заголовков контролов
|
||
/// </summary>
|
||
private event Action<int> SetTitleWidth;
|
||
|
||
/// <summary>
|
||
/// Событие установки значения
|
||
/// </summary>
|
||
private event Action<object> SetValues;
|
||
|
||
/// <summary>
|
||
/// Событие сброса значения в исходное состояние
|
||
/// </summary>
|
||
private event Action DropValues;
|
||
|
||
/// <summary>
|
||
/// Событие проверки заполненности контрола
|
||
/// </summary>
|
||
private event Func<bool> CheckValues;
|
||
|
||
/// <summary>
|
||
/// Событие получения значения из контрола
|
||
/// </summary>
|
||
private event Action<object> GetValues;
|
||
|
||
private E Element
|
||
{
|
||
get { return _element; }
|
||
set
|
||
{
|
||
try
|
||
{
|
||
_element = value;
|
||
if (_element != null)
|
||
{
|
||
SetValues?.Invoke(_element);
|
||
if (tabControl.Visible)
|
||
{
|
||
foreach (TabPage page in tabControl.TabPages)
|
||
{
|
||
if (page.Name == tabPageMain.Name)
|
||
{
|
||
continue;
|
||
}
|
||
if (page.Controls[0] is IControlChildEntity cntrl)
|
||
{
|
||
cntrl.ParentId = _element.Id;
|
||
cntrl.Open(new ControlOpenModel { OpenMode = ControlOpenMode.Child });
|
||
}
|
||
}
|
||
}
|
||
}
|
||
_haveChages = false;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
DialogHelper.MessageException(ex.Message, $"{Title}. Ошибка при установки значений");
|
||
}
|
||
}
|
||
}
|
||
|
||
public GenericControlEntityElement()
|
||
{
|
||
InitializeComponent();
|
||
InitEvents();
|
||
_businessLogic = DependencyManager.Instance.Resolve<BL>();
|
||
_controlViewEntityElement = this;
|
||
}
|
||
|
||
public void OpenControl(ControlOpenModel model)
|
||
{
|
||
if (model.CloseElement != null)
|
||
{
|
||
CloseElementEvent += model.CloseElement;
|
||
}
|
||
if (panelContainer.Controls.Count == 0)
|
||
{
|
||
try
|
||
{
|
||
Configurate(GetConfig());
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
DialogHelper.MessageException(ex.Message, $"{Title}. Ошибка при конфигурации");
|
||
}
|
||
}
|
||
if (model.ElementId.HasValue)
|
||
{
|
||
Element = _businessLogic.GetElement(new G { Id = model.ElementId });
|
||
if (Element == null)
|
||
{
|
||
DialogHelper.MessageException(_businessLogic.Errors, $"{Title}. Ошибки при получении элемента");
|
||
}
|
||
}
|
||
Dock = DockStyle.Fill;
|
||
}
|
||
|
||
public IControl GetInstanceControl() => _genericControlViewEntityElement?.GetInstanceGenericControl();
|
||
|
||
public string SaveControlToXml() => new XElement("Control",
|
||
new XAttribute("Type", GetType().FullName),
|
||
new XAttribute("ControlId", ControlId),
|
||
new XAttribute("Title", Title)).ToString();
|
||
|
||
public void LoadControlFromXml(string xml)
|
||
{
|
||
var control = XElement.Parse(xml).Element("Control");
|
||
ControlId = new Guid(control.Attribute("ControlId").Value.ToString());
|
||
Title = control.Attribute("Title").Value.ToString();
|
||
}
|
||
|
||
private void InitEvents()
|
||
{
|
||
toolStripButtonSave.Click += (object sender, EventArgs e) => { Save(); };
|
||
toolStripButtonReload.Click += (object sender, EventArgs e) =>
|
||
{
|
||
if (DialogHelper.MessageQuestion("Отменить все внесенные изменения?") == DialogResult.Yes)
|
||
{
|
||
try
|
||
{
|
||
DropValues?.Invoke();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
DialogHelper.MessageException(ex.Message, $"{Title}. Ошибка при сбросе значений");
|
||
}
|
||
}
|
||
};
|
||
toolStripButtonClose.Click += (object sender, EventArgs e) =>
|
||
{
|
||
if (_haveChages && DialogHelper.MessageQuestion("Имеется несохраненные данные, вы действительно хотите закрыть элемент?", "Закрытие элемента") == DialogResult.Yes)
|
||
{
|
||
if (!Save())
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
CloseElementEvent?.Invoke(ControlId);
|
||
Dispose();
|
||
};
|
||
}
|
||
|
||
private void Configurate(ControlViewEntityElementConfiguration config)
|
||
{
|
||
// Загрузка подпунктов в контекстное меню и в пункт меню "Действие"
|
||
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);
|
||
ToolStripMenuItem itemContext = new() { Text = elem.Value.Title, Name = elem.Key };
|
||
itemContext.Click += elem.Value.Event;
|
||
contextMenuStripElement.Items.Add(itemContext);
|
||
}
|
||
}
|
||
// либо скрытие пункта, если не предусмотренно подпунктов
|
||
else
|
||
{
|
||
toolStripSplitButtonActions.Visible = false;
|
||
toolStripSeparator1.Visible = false;
|
||
}
|
||
var attributeClass = typeof(E).GetCustomAttribute<ViewModelControlElementClassAttribute>();
|
||
if (attributeClass == null)
|
||
{
|
||
return;
|
||
}
|
||
tabControl.Visible = attributeClass.HaveDependenceEntities;
|
||
panelContainer.Visible = !attributeClass.HaveDependenceEntities;
|
||
Width = attributeClass.Width != 0 ? attributeClass.Width : _defaultControlWidth;
|
||
|
||
int positionY = 5;
|
||
int positionX = 5;
|
||
int interval = 15;
|
||
|
||
int titleWidth = 0;
|
||
|
||
foreach (var property in typeof(E).GetProperties())
|
||
{
|
||
var attribute = property.GetCustomAttribute<ViewModelControlElementPropertyAttribute>();
|
||
if (attribute != null)
|
||
{
|
||
AbstractBaseControl control = null;
|
||
switch (attribute.ControlType)
|
||
{
|
||
case ControlType.ControlString:
|
||
control = new BaseControlString(property.Name, attribute.MustHaveValue, attribute.ReadOnly, attribute.MaxLength);
|
||
break;
|
||
case ControlType.ControlText:
|
||
control = new BaseControlText(property.Name, attribute.MustHaveValue, attribute.ReadOnly, attribute.MaxLength, attribute.Height);
|
||
break;
|
||
case ControlType.ControlInt:
|
||
control = new BaseControlInt(property.Name, attribute.MustHaveValue, attribute.ReadOnly, attribute.MinValue, attribute.MaxValue);
|
||
break;
|
||
case ControlType.ControlDecimal:
|
||
control = new BaseControlDecimal(property.Name, attribute.MustHaveValue, attribute.ReadOnly, attribute.MinValue,
|
||
attribute.MaxValue, attribute.DecimalPlaces);
|
||
break;
|
||
case ControlType.ControlBool:
|
||
control = new BaseControlBool(property.Name, attribute.MustHaveValue, attribute.ReadOnly);
|
||
break;
|
||
case ControlType.ControlDateTime:
|
||
control = new BaseControlDateTime(property.Name, attribute.MustHaveValue, attribute.ReadOnly, attribute.MinDate,
|
||
attribute.MaxDate, attribute.CustomDateFormat);
|
||
break;
|
||
case ControlType.ControlImage:
|
||
control = new BaseControlImage(property.Name, attribute.MustHaveValue, attribute.ReadOnly, attribute.Width, attribute.Height);
|
||
break;
|
||
case ControlType.ControlEnum:
|
||
control = new BaseControlEnum(property.Name, attribute.MustHaveValue, attribute.ReadOnly, property.PropertyType);
|
||
break;
|
||
case ControlType.ControlGuid:
|
||
if (attribute.ControlTypeObject.IsNotEmpty() && Type.GetType(attribute.ControlTypeObject) != null)
|
||
{
|
||
control = new BaseControlGuid(property.Name, attribute.MustHaveValue, attribute.ReadOnly,
|
||
DependencyManager.Instance.Resolve(Type.GetType(attribute.ControlTypeObject)) as IControlEntitySelectable,
|
||
property.Name == ParentPropertyName ? ParentId : null);
|
||
}
|
||
break;
|
||
}
|
||
if (control == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var widthTitle = control.SetTitle(attribute.DisplayName);
|
||
if (widthTitle > titleWidth)
|
||
{
|
||
titleWidth = widthTitle;
|
||
}
|
||
|
||
control.OnValueChangeEvent += () => { _haveChages = true; };
|
||
SetValues += control.SetValue;
|
||
DropValues += control.DropValue;
|
||
CheckValues += control.CheckValue;
|
||
SetTitleWidth += control.SetTitleWidth;
|
||
GetValues += control.GetValue;
|
||
|
||
control.Location = new System.Drawing.Point(positionX, positionY);
|
||
control.Width = Width - positionX * 2 - (tabControl.Visible ? 10 : 0);
|
||
control.Anchor = AnchorStyles.Top | AnchorStyles.Left;
|
||
if (panelContainer.Visible)
|
||
{
|
||
control.Anchor |= AnchorStyles.Right;
|
||
}
|
||
positionY += control.Height + interval;
|
||
|
||
if (panelContainer.Visible)
|
||
{
|
||
panelContainer.Controls.Add(control);
|
||
}
|
||
if (tabControl.Visible)
|
||
{
|
||
tabPageMain.Controls.Add(control);
|
||
}
|
||
}
|
||
}
|
||
|
||
SetTitleWidth(titleWidth);
|
||
Height = attributeClass.Height != 0 ? attributeClass.Height : positionY;
|
||
|
||
if (attributeClass.HaveDependenceEntities)
|
||
{
|
||
var attrDependences = typeof(E).GetCustomAttributes<ViewModelControlElementDependenceEntityAttribute>();
|
||
if (attrDependences != null)
|
||
{
|
||
foreach (var attr in attrDependences)
|
||
{
|
||
if (DependencyManager.Instance.Resolve(Type.GetType(attr.ControlTypeObject)) is IControlChildEntity control)
|
||
{
|
||
var cntrl = control.GetInstance() as IControlChildEntity;
|
||
cntrl.ParentPropertyName = attr.ParentPropertyName;
|
||
//cntrl.Open(null);
|
||
var tabPage = new TabPage
|
||
{
|
||
Location = new System.Drawing.Point(4, 24),
|
||
Name = "tabPage",
|
||
Padding = new Padding(3),
|
||
Size = new System.Drawing.Size(122, 99),
|
||
TabIndex = 0,
|
||
Text = attr.Title,
|
||
UseVisualStyleBackColor = true
|
||
};
|
||
tabPage.Controls.Add(cntrl as UserControl);
|
||
|
||
tabControl.TabPages.Add(tabPage);
|
||
if (attr.IsActive)
|
||
{
|
||
tabPage.Select();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private bool Save()
|
||
{
|
||
if (CheckValues.GetInvocationList().Select(x => (bool)x.DynamicInvoke()).ToList().Any(x => !x))
|
||
{
|
||
return false;
|
||
}
|
||
var model = Element == null ? new S() : Mapper.MapToClass<E, S>(Element, true);
|
||
try
|
||
{
|
||
GetValues(model);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
DialogHelper.MessageException(ex.Message, "Ошибка при получении значений");
|
||
}
|
||
|
||
if (model != null)
|
||
{
|
||
if (Element == null)
|
||
{
|
||
Element = _businessLogic.Create(model);
|
||
}
|
||
else
|
||
{
|
||
Element = _businessLogic.Update(model);
|
||
}
|
||
|
||
if (Element == null)
|
||
{
|
||
DialogHelper.MessageException(_businessLogic.Errors, "Ошибки при сохранении элемента");
|
||
return false;
|
||
}
|
||
|
||
_haveChages = false;
|
||
DialogHelper.MessageInformation("Сохранение прошло успешно", "Сообщение");
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
private ControlViewEntityElementConfiguration GetConfig() => _genericControlViewEntityElement?.GetConfigControl();
|
||
|
||
protected bool FillModel(S model)
|
||
{
|
||
if (CheckValues.GetInvocationList().Select(x => (bool)x.DynamicInvoke()).ToList().Any(x => !x))
|
||
{
|
||
return false;
|
||
}
|
||
try
|
||
{
|
||
GetValues(model);
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
DialogHelper.MessageException(ex.Message, "Ошибка при получении значений");
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
}
|