Compare commits

...

8 Commits
main ... test2

Author SHA1 Message Date
Marselchi
38deda13cf Фикс бага 2024-10-15 23:23:05 +04:00
Marselchi
e4134c7dfe Типа всё наверное 2024-10-13 18:54:33 +04:00
Marselchi
a73f9deec9 тестим 2024-10-07 10:50:24 +04:00
Marselchi
b895e2f257 вторая лаба 2024-10-07 10:18:41 +04:00
Marselchi
7204b0c1c9 Сдано йо 2024-09-06 10:48:03 +04:00
Marselchi
0b6c2765ec и ещё 2024-09-05 23:01:49 +04:00
Marselchi
1a1731a44b Лютый фикс дерева 2024-09-05 22:57:01 +04:00
Marselchi
a56ed0c96a Омегакоммит 2024-09-05 22:14:26 +04:00
37 changed files with 2202 additions and 0 deletions

View File

@ -5,6 +5,8 @@ VisualStudioVersion = 17.9.34714.143
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomComponents", "CustomComponents\CustomComponents.csproj", "{974043F1-1F51-4471-B016-65A3311CE956}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsTestApp", "WinFormsTestApp\WinFormsTestApp.csproj", "{D5BFCAA1-24BB-433E-833D-255FFF6DD972}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,6 +17,10 @@ Global
{974043F1-1F51-4471-B016-65A3311CE956}.Debug|Any CPU.Build.0 = Debug|Any CPU
{974043F1-1F51-4471-B016-65A3311CE956}.Release|Any CPU.ActiveCfg = Release|Any CPU
{974043F1-1F51-4471-B016-65A3311CE956}.Release|Any CPU.Build.0 = Release|Any CPU
{D5BFCAA1-24BB-433E-833D-255FFF6DD972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5BFCAA1-24BB-433E-833D-255FFF6DD972}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5BFCAA1-24BB-433E-833D-255FFF6DD972}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5BFCAA1-24BB-433E-833D-255FFF6DD972}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -7,4 +7,44 @@
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<COMReference Include="Microsoft.Office.Core">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>8</VersionMinor>
<VersionMajor>2</VersionMajor>
<Guid>2df8d04c-5bfa-101b-bde5-00aa0044de52</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
<COMReference Include="Microsoft.Office.Interop.Excel">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>9</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>00020813-0000-0000-c000-000000000046</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
<COMReference Include="Microsoft.Office.Interop.Word">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>7</VersionMinor>
<VersionMajor>8</VersionMajor>
<Guid>00020905-0000-0000-c000-000000000046</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspose.Words" Version="24.9.0" />
<PackageReference Include="DocumentFormat.OpenXml" Version="3.1.0" />
<PackageReference Include="DocX" Version="3.0.0" />
<PackageReference Include="Microsoft.Chart.Controls" Version="4.7.2046" />
<PackageReference Include="Spire.Doc" Version="12.8.12" />
<PackageReference Include="System.Data.OleDb" Version="8.0.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomComponents.NonViewComponents.Enums
{
public enum PieChartLegendAlign
{
None,
Left,
Top,
Right,
Bottom
}
}

View File

@ -0,0 +1,36 @@
namespace CustomComponents.NonViewComponents
{
partial class ImageWord
{
/// <summary>
/// Обязательная переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором компонентов
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xceed.Words.NET;
using CustomComponents.NonViewComponents.SupportClasses;
using CustomComponents.NonViewComponents.Logic;
namespace CustomComponents.NonViewComponents
{
public partial class ImageWord : Component
{
public ImageWord()
{
InitializeComponent();
}
public ImageWord(IContainer container)
{
container.Add(this);
InitializeComponent();
}
/// <summary>
/// Добавляет изображения в *.docx документ. Пример: в документе указан текст "TEXT". Метод добавит после первого попавшегося "TEXT" все изображения по порядку.
/// </summary>
/// <param name="pathToFile">Путь к документу</param>
/// <param name="paragraph">Текст, содержащийся в параграфе документа</param>
/// <param name="images">Изображения</param>
public void AddImages(string pathToFile, string paragraph, IEnumerable<DocImage> images)
{
if (!_check(pathToFile, paragraph, images)) throw new Exception("Wrong data!");
using (var logic = new WordImageLogic(DocX.Load(pathToFile)))
{
logic.AddImages(paragraph, images);
}
}
private bool _check(string pathToFile, string paragraph, IEnumerable<DocImage> images)
{
return !string.IsNullOrWhiteSpace(pathToFile)
&& !string.IsNullOrWhiteSpace(paragraph)
&& images.All(image => !string.IsNullOrWhiteSpace(image.Path));
}
}
}

View File

@ -0,0 +1,34 @@
using CustomComponents.NonViewComponents.SupportClasses;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xceed.Words.NET;
namespace CustomComponents.NonViewComponents.Logic
{
public class WordImageLogic : WordLogicBase
{
public WordImageLogic(DocX doc) : base(doc)
{
}
public void AddImages(string paragraph, IEnumerable<DocImage> images)
{
var p = findParagraph(paragraph);
foreach (var image in images.Reverse())
{
var img = _doc.AddImage(image.Path);
var picture = image.Height.HasValue && image.Width.HasValue
? img.CreatePicture((float)image.Height, (float)image.Width)
: img.CreatePicture();
var newParagraph = p.InsertParagraphAfterSelf("\n");
newParagraph.InsertPicture(picture);
}
_doc.Save();
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xceed.Document.NET;
using Xceed.Words.NET;
namespace CustomComponents.NonViewComponents.Logic
{
public abstract class WordLogicBase : IDisposable
{
protected DocX _doc;
public WordLogicBase(DocX doc)
{
_doc = doc;
}
public void Dispose()
{
_doc.Dispose();
}
protected Paragraph findParagraph(string paragraph)
=> _doc.Paragraphs.FirstOrDefault(p => p.Text.Contains(paragraph))
?? throw new Exception($"Paragraph '{paragraph}' not found.");
}
}

View File

@ -0,0 +1,99 @@
using CustomComponents.NonViewComponents.Enums;
using CustomComponents.NonViewComponents.SupportClasses;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Word = Microsoft.Office.Interop.Word;
using Excel = Microsoft.Office.Interop.Excel;
using Xceed.Words.NET;
namespace CustomComponents.NonViewComponents.Logic
{
public class WordPieChartLogic
{
public void AddDiagram(PieChartData diagramInfo)
{
var wordApp = new Word.Application();
var document = wordApp.Documents.Add();
AddTitle(document, diagramInfo.DocumentTitle);
AddChart(document, diagramInfo);
document.SaveAs2(diagramInfo.FileName);
wordApp.Quit();
}
private void AddTitle(Word.Document document, string title)
{
var paragraph = document.Paragraphs.Add();
paragraph.Range.Text = title;
paragraph.Range.Font.Size = 24;
paragraph.Range.Font.Bold = 1;
paragraph.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Range.InsertParagraphAfter();
}
private void AddChart(Word.Document document, PieChartData diagramInfo)
{
var paragraph = document.Paragraphs.Add();
var chartShape = document.InlineShapes.AddChart2(-1, (Microsoft.Office.Core.XlChartType)Excel.XlChartType.xlPie, paragraph.Range); // Круговая диаграмма
var chart = chartShape.Chart;
chart.HasTitle = true;
chart.ChartTitle.Text = diagramInfo.DiagramTitle;
var chartSeriesCollection = chart.SeriesCollection();
for (int i = chartSeriesCollection.Count; i >= 1; i--)
{
chartSeriesCollection.Item(i).Delete();
}
var categoriesX = diagramInfo.CategoriesX.ToArray();
for (int i = 0; i < diagramInfo.SeriesData.Count; i++)
{
var seriesInfo = diagramInfo.SeriesData[i];
var series = chartSeriesCollection.NewSeries();
series.Name = seriesInfo.SeriesName;
series.Values = seriesInfo.ValuesY.ToArray();
series.XValues = categoriesX;
if (series.Points().Count >= seriesInfo.ValuesY.Count)
{
for (int j = 1; j <= seriesInfo.ValuesY.Count; j++)
{
var point = series.Points(j);
point.Format.Fill.ForeColor.RGB = ColorTranslator.ToOle(seriesInfo.Color);
}
}
}
chart.HasLegend = true;
chart.Legend.Position = diagramInfo.LegendLayout switch
{
PieChartLegendAlign.Left => Word.XlLegendPosition.xlLegendPositionLeft,
PieChartLegendAlign.Top => Word.XlLegendPosition.xlLegendPositionTop,
PieChartLegendAlign.Right => Word.XlLegendPosition.xlLegendPositionRight,
PieChartLegendAlign.Bottom => Word.XlLegendPosition.xlLegendPositionBottom,
_ => Word.XlLegendPosition.xlLegendPositionBottom,
};
chart.ChartData.Workbook.Application.Quit();
}
private void SetSeriesColor(dynamic series, Color color)
{
series.Format.Line.ForeColor.RGB = ColorTranslator.ToOle(color);
series.Format.Fill.ForeColor.RGB = ColorTranslator.ToOle(color);
}
}
}

View File

@ -0,0 +1,115 @@
using CustomComponents.ViewComponents.Exceptions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Xceed.Document.NET;
using Xceed.Words.NET;
namespace CustomComponents.NonViewComponents.Logic
{
public class WordTableLogic : WordLogicBase
{
private const float DEF_HEIGHT = 20;
public WordTableLogic(DocX doc) : base(doc)
{
}
public void AddTable<T>(string paragraph, IEnumerable<(string, string, string)> header,
IEnumerable<float?>? rowHeight, IEnumerable<T> values)
{
var p = findParagraph(paragraph);
var table = _doc.AddTable(header.Count(), values.Count() + 2);
table.Alignment = Alignment.center;
_addHeader(table, header);
_fillTable(table, values, header);
_formatHeader(table, header, rowHeight);
p.InsertTableAfterSelf(table);
_doc.Save();
}
private void _addHeader(Table table, IEnumerable<(string, string, string)> header)
{
for (int i = 0; i < header.Count(); i++)
{
var headerElem = header.ElementAtOrDefault(i);
table.Rows[i].Cells[0].Paragraphs[0].Append(headerElem.Item1);
table.Rows[i].Cells[1].Paragraphs[0].Append(headerElem.Item2);
}
}
private void _formatHeader(Table table, IEnumerable<(string, string,string)> header, IEnumerable<float?>? rowHeight)
{
for (int i = 0; i < header.Count(); i++)
{
var headerElem = header.ElementAtOrDefault(i);
if (string.IsNullOrWhiteSpace(headerElem.Item2))
{
table.Rows[i].MergeCells(0, 1);
}
var nextElem = header.ElementAtOrDefault(i + 1);
if (headerElem.Item1 == nextElem.Item1)
{
table.MergeCellsInColumn(0, i, i + 1);
}
table.Rows[i].Height = rowHeight?.ElementAtOrDefault(i) ?? DEF_HEIGHT;
}
}
private void _fillTable<T>(Table table, IEnumerable<T> values, IEnumerable<(string, string, string)> header)
{
for (int i = 0; i < values.Count(); i++)
{
var data = _getValueData(values.ElementAt(i), header);
_addData(table, i + 2, data);
}
}
private void _addData(Table table, int indexColumn, Dictionary<string, object> data)
{
for (int i = 0; i < data.Count; i++)
{
foreach (var cell in data)
{
if (table.Rows[i].Cells[0].Paragraphs[0].Text == cell.Key
|| table.Rows[i].Cells[1].Paragraphs[0].Text == cell.Key)
{
table.Rows[i].Cells[indexColumn].Paragraphs[0].Append(cell.Value.ToString());
}
}
}
}
private Dictionary<string, object> _getValueData<T>(T value, IEnumerable<(string, string, string)> header)
{
var result = new Dictionary<string, object>();
if (value is null)
{
throw new ArgumentNullException($"The {nameof(value)} is null.");
}
if (value.GetType().GetProperties() is null)
{
throw new ArgumentNullException($"Properties in {nameof(value)} is null");
}
foreach (var h in header)
{
var headerElem = string.IsNullOrWhiteSpace(h.Item2) ? h.Item1 : h.Item2;
var propVal = h.Item3 as string;
result[headerElem] = value.GetType().GetProperty(propVal).GetValue(value, null);
}
return result;
}
}
}

View File

@ -0,0 +1,36 @@
namespace CustomComponents.NonViewComponents
{
partial class PieChartWord
{
/// <summary>
/// Обязательная переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором компонентов
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@ -0,0 +1,70 @@
using CustomComponents.NonViewComponents.Enums;
using CustomComponents.NonViewComponents.Logic;
using CustomComponents.NonViewComponents.SupportClasses;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xceed.Words.NET;
using Word = Microsoft.Office.Interop.Word;
using Excel = Microsoft.Office.Interop.Excel;
namespace CustomComponents.NonViewComponents
{
public partial class PieChartWord : Component
{
public PieChartWord()
{
InitializeComponent();
}
public PieChartWord(IContainer container)
{
container.Add(this);
InitializeComponent();
}
/// <summary>
/// Добавляет диаграмму данных после параграфа в *.docx документ.
/// </summary>
/// <param name="diagramInfo">Содержит информацию о документе и диаграмме</param>
public void CreateDiagramDocument(PieChartData diagramInfo)
{
_check(diagramInfo);
WordPieChartLogic logic = new();
logic.AddDiagram(diagramInfo);
}
private void _check(PieChartData diagramInfo)
{
if (string.IsNullOrEmpty(diagramInfo.FileName) || string.IsNullOrEmpty(diagramInfo.DocumentTitle) ||
string.IsNullOrEmpty(diagramInfo.DiagramTitle) || diagramInfo.CategoriesX == null ||
diagramInfo.CategoriesX.Count == 0 || diagramInfo.SeriesData == null ||
diagramInfo.SeriesData.Count == 0)
{
throw new ArgumentException("Not all data for diagram");
}
foreach (var series in diagramInfo.SeriesData)
{
if (string.IsNullOrEmpty(series.SeriesName))
{
throw new ArgumentException("Series name cant be null");
}
if (series.ValuesY == null || series.ValuesY.Count == 0)
{
throw new ArgumentException($"Y series values '{series.SeriesName}' is null");
}
if (diagramInfo.CategoriesX.Count != series.ValuesY.Count)
{
throw new ArgumentException($"Categories X and series Y count '{series.SeriesName}' are not equal");
}
}
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomComponents.NonViewComponents.SupportClasses
{
public class DocImage
{
/// <summary>
/// Путь к изображению
/// </summary>
public string Path { get; set; } = string.Empty;
/// <summary>
/// Высота изображения. Может отсутствовать
/// </summary>
public float? Height { get; set; }
/// <summary>
/// Длина изображения. Может отсутствовать
/// </summary>
public float? Width { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CustomComponents.NonViewComponents.Enums;
namespace CustomComponents.NonViewComponents.SupportClasses
{
public class PieChartData
{
/// <summary>
/// Путь до файла
/// </summary>
public string FileName { get; set; } = string.Empty;
/// <summary>
/// После чего вставить диаграмму
/// </summary>
public string DocumentTitle { get; set; } = string.Empty;
/// <summary>
/// Заголовок диаграммы
/// </summary>
public string DiagramTitle { get; set; } = string.Empty;
/// <summary>
/// Расположение легенды диаграммы
/// </summary>
public PieChartLegendAlign LegendLayout { get; set; }
/// <summary>
/// Категории
/// </summary>
public List<string> CategoriesX { get; set; } = new();
/// <summary>
/// Серии
/// </summary>
public List<SeriesData> SeriesData { get; set; } = new();
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomComponents.NonViewComponents.SupportClasses
{
public class SeriesData
{
/// <summary>
/// Название серии
/// </summary>
public string SeriesName { get; set; } = string.Empty;
/// <summary>
/// Значения
/// </summary>
public List<double> ValuesY { get; set; } = new();
/// <summary>
/// Цвет
/// </summary>
public Color Color { get; set; }
}
}

View File

@ -0,0 +1,36 @@
namespace CustomComponents.NonViewComponents
{
partial class TableWord
{
/// <summary>
/// Обязательная переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором компонентов
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@ -0,0 +1,73 @@
using CustomComponents.NonViewComponents.Logic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xceed.Words.NET;
namespace CustomComponents.NonViewComponents
{
public partial class TableWord : Component
{
public TableWord()
{
InitializeComponent();
}
public TableWord(IContainer container)
{
container.Add(this);
InitializeComponent();
}
/// <summary>
/// Добавляет таблицу данных после параграфа в *.docx документ.
/// Свойства объектов коллекции должны иметь атрибут <c>[DisplayName(string)]</c>.
/// Значения атрибутов должны соответствовать шапке таблицы.
/// Если в коллекции шапки ("Имя", ""), то ячейки объединяются в одну колонку.
/// Если подряд идут те же названия: ("Личная информация", "Фио"), ("Личная информация", "Город"), то ячейки объединяются в одну строку.
/// </summary>
/// <typeparam name="T">Любой класс, главное, чтобы свойства имели атрибут [DisplayName(string)]</typeparam>
/// <param name="pathToFile">Путь к документу</param>
/// <param name="paragraph">Текст внутри параграфа</param>
/// <param name="header">Информация о шапке</param>
/// <param name="rowHeight">Высота строки. Может быть null.
/// Если не указать в какой-то строке значение (поставить null, вместо float значения), то будет установлена высота по умолчанию</param>
/// <param name="values">Коллекция объектов, которые будут добавлены в таблицу</param>
public void AddTable<T>(string pathToFile, string paragraph,
IEnumerable<(string, string, string)> header,
IEnumerable<float?>? rowHeight,
IEnumerable<T> values
)
{
_check(pathToFile, paragraph, header, rowHeight, values);
using (var logic = new WordTableLogic(DocX.Load(pathToFile)))
{
logic.AddTable(paragraph, header, rowHeight, values);
}
}
private void _check<T>(string pathToFile, string paragraph,
IEnumerable<(string, string, string)> header,
IEnumerable<float?>? rowHeight,
IEnumerable<T> values)
{
if (string.IsNullOrWhiteSpace(pathToFile)
|| string.IsNullOrWhiteSpace(paragraph))
{
throw new ArgumentNullException("The path to file or paragraph is null or empty.");
}
if (rowHeight is not null)
{
if (rowHeight.Count() != header.Count())
{
throw new ArgumentException($"{nameof(rowHeight)} is not of equal length with {nameof(header)}");
}
}
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomComponents.ViewComponents.Attributes
{
public class AlwaysCreateAttribute : Attribute
{
public AlwaysCreateAttribute()
{ }
}
}

View File

@ -0,0 +1,59 @@
namespace CustomComponents
{
partial class CustomCheckedListBox
{
/// <summary>
/// Обязательная переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором компонентов
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary>
private void InitializeComponent()
{
checkedListBox = new CheckedListBox();
SuspendLayout();
//
// checkedListBox
//
checkedListBox.CheckOnClick = true;
checkedListBox.Dock = DockStyle.Fill;
checkedListBox.FormattingEnabled = true;
checkedListBox.Location = new Point(0, 0);
checkedListBox.Name = "checkedListBox";
checkedListBox.Size = new Size(150, 120);
checkedListBox.TabIndex = 0;
checkedListBox.SelectedIndexChanged += checkedListBox_SelectedIndexChanged;
//
// CustomCheckedListBox
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(checkedListBox);
Name = "CustomCheckedListBox";
Size = new Size(150, 120);
ResumeLayout(false);
}
#endregion
private CheckedListBox checkedListBox;
}
}

View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CustomComponents
{
public partial class CustomCheckedListBox : UserControl
{
public CheckedListBox.ObjectCollection DataList
{
get => checkedListBox.Items;
}
public string SelectedValue
{
get
{
if (checkedListBox.Items.Count == 0)
{
return string.Empty;
}
if (checkedListBox.SelectedItem == null)
{
return string.Empty;
}
return checkedListBox.SelectedItem.ToString()!;
}
set
{
int index = checkedListBox.Items.IndexOf(value);
if (index == -1)
{
return;
}
checkedListBox.SelectedItem = value;
checkedListBox.SetItemChecked(index, true);
}
}
private event EventHandler? _selectChanged;
public event EventHandler SelectChanged
{
add { _selectChanged += value; }
remove { _selectChanged -= value; }
}
public CustomCheckedListBox()
{
InitializeComponent();
}
public void ClearList()
{
checkedListBox.Items.Clear();
}
private void checkedListBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (checkedListBox.CheckedItems.Count > 1)
{
foreach (int index in checkedListBox.CheckedIndices)
{
if (index != checkedListBox.SelectedIndex)
{
checkedListBox.SetItemChecked(index, false);
}
}
}
_selectChanged?.Invoke(this, EventArgs.Empty);
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,60 @@
namespace CustomComponents
{
partial class CustomNumericUpDown
{
/// <summary>
/// Обязательная переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором компонентов
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary>
private void InitializeComponent()
{
numericUpDown = new NumericUpDown();
((System.ComponentModel.ISupportInitialize)numericUpDown).BeginInit();
SuspendLayout();
//
// numericUpDown
//
numericUpDown.Dock = DockStyle.Fill;
numericUpDown.Location = new Point(0, 0);
numericUpDown.Maximum = new decimal(new int[] { 0, 0, 0, 0 });
numericUpDown.Name = "numericUpDown";
numericUpDown.Size = new Size(150, 27);
numericUpDown.TabIndex = 0;
numericUpDown.ValueChanged += numericUpDown_ValueChanged;
//
// CustomNumericUpDown
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(numericUpDown);
Name = "CustomNumericUpDown";
Size = new Size(150, 27);
((System.ComponentModel.ISupportInitialize)numericUpDown).EndInit();
ResumeLayout(false);
}
#endregion
private NumericUpDown numericUpDown;
}
}

View File

@ -0,0 +1,93 @@
using CustomComponents.ViewComponents.Exceptions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CustomComponents
{
public partial class CustomNumericUpDown : UserControl
{
private event EventHandler? _valueChanged;
public event EventHandler ValueChanged
{
add { _valueChanged += value; }
remove { _valueChanged -= value; }
}
public decimal? max = null;
public decimal? min = null;
public decimal? Max
{
get
{
return max;
}
set
{
if (value == null) return;
max = value;
numericUpDown.Maximum = (decimal)value;
}
}
public decimal? Min
{
get
{
return min;
}
set
{
if (value == null) return;
min = value;
numericUpDown.Minimum = (decimal)value;
}
}
public decimal? Value
{
get
{
if (Max == null || Min == null)
{
throw new RangeNullException("Range is not defined");
}
if (numericUpDown.Value < Min || numericUpDown.Value > Max)
{
throw new ArgumentOutOfRangeException("Value is less than min or more than max");
}
return numericUpDown.Value;
}
set
{
if (Max == null || Min == null)
{
return;
}
if (value < Min || value > Max)
{
return;
}
numericUpDown.Value = (decimal)value;
}
}
public CustomNumericUpDown()
{
InitializeComponent();
}
private void numericUpDown_ValueChanged(object sender, EventArgs e)
{
_valueChanged?.Invoke(this, e);
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,55 @@
namespace CustomComponents
{
partial class CustomTreeView
{
/// <summary>
/// Обязательная переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором компонентов
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary>
private void InitializeComponent()
{
treeView = new TreeView();
SuspendLayout();
//
// treeView
//
treeView.Dock = DockStyle.Fill;
treeView.Location = new Point(0, 0);
treeView.Name = "treeView";
treeView.Size = new Size(150, 150);
treeView.TabIndex = 0;
//
// CustomTreeView
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(treeView);
Name = "CustomTreeView";
ResumeLayout(false);
}
#endregion
private TreeView treeView;
}
}

View File

@ -0,0 +1,153 @@
using CustomComponents.ViewComponents.Exceptions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using CustomComponents.ViewComponents.Attributes;
namespace CustomComponents
{
public partial class CustomTreeView : UserControl
{
public int SelectedTreeNodeID
{
get => treeView.SelectedNode.Index;
set => treeView.SelectedNode = treeView.Nodes[value];
}
public List<string>? Hierarchy { get; set; }
public CustomTreeView()
{
InitializeComponent();
}
public void AddNode<T>(T obj, string propertyName)
{
if (Hierarchy == null)
{
throw new HierarchyNullException("Hierarchy is null");
}
if (obj == null)
{
throw new ArgumentNullException("Added object is null");
}
int index = Hierarchy.IndexOf(propertyName);
if (index == -1)
{
throw new PropertyNullException("Property not found in hierarchy");
}
var values = _getValuesWithStructure(obj, propertyName);
var treeNode = new TreeNode();
_addNodesToTreeNode(treeView.Nodes, treeNode.Nodes);
var nodes = _addElementsToParent(values, treeNode);
treeView.Nodes.Clear();
_addNodesToTreeNode(nodes.Nodes, treeView.Nodes);
}
private void _addNodesToTreeNode(TreeNodeCollection fromNodeCollection, TreeNodeCollection toNodeCollection)
{
for (int i = 0; i < fromNodeCollection.Count; i++)
{
var node = fromNodeCollection[i].Clone() as TreeNode;
toNodeCollection.Add(node);
}
}
private Dictionary<string, (object, bool)> _getValuesWithStructure<T>(T obj, string propertyName)
{
PropertyInfo[]? properties = obj?.GetType().GetProperties();
var dict = new Dictionary<string, (object, bool)>();
// Получаем все значения свойств в структурированном виде (относительно иерархии)
foreach (var elem in Hierarchy!)
{
PropertyInfo? prop = properties?.Single(prop => prop.Name == elem);
if(prop == null)
{
throw new PropertyNullException(nameof(prop));
}
// Получаем атрибут, отвечающий за необходимость создания новой ветки
var atr = prop.GetCustomAttributes()?.SingleOrDefault(atr => atr is AlwaysCreateAttribute);
dict[elem] = (prop.GetValue(obj)!, atr == null ? false : true);
if (elem == propertyName)
{
break;
}
}
return dict;
}
private TreeNode _addElementsToParent(Dictionary<string, (object, bool)> elements, TreeNode parent)
{
if (elements.Count == 0)
{
return parent;
}
var firstElem = elements.First();
// Получаем элемент
var child = parent.Nodes
.Cast<TreeNode>()
.SingleOrDefault(node => node.Text == (string)firstElem.Value.Item1);
if (child != null && !firstElem.Value.Item2)
{
elements.Remove(firstElem.Key);
return _addElementsToParent(elements, child).Parent;
}
else
{
var newChild = new TreeNode(firstElem.Value.Item1?.ToString() ?? string.Empty);
newChild.Tag = new Tuple<string, object>(firstElem.Key, firstElem.Value.Item1!);
elements.Remove(firstElem.Key);
parent.Nodes.Add(_addElementsToParent(elements, newChild));
return parent;
}
}
public T GetSelectedNode<T>()
where T : new()
{
if (Hierarchy == null)
{
throw new HierarchyNullException("Hierarchy is null");
}
if (treeView.SelectedNode == null)
{
return new T();
}
return _getNode(new T(), treeView.SelectedNode);
}
private T _getNode<T>(T obj, TreeNode node)
{
if (node != null && node.Tag != null)
{
var tag = node.Tag as Tuple<string, object>;
var property = obj?.GetType().GetProperty(tag!.Item1);
property?.SetValue(obj, Convert.ChangeType(tag!.Item2, property.PropertyType));
_getNode(obj, node.Parent);
}
return obj;
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,17 @@
namespace CustomComponents.ViewComponents.Exceptions
{
public class AttributeNullException : Exception
{
public AttributeNullException()
{
}
public AttributeNullException(string message) : base(message)
{
}
public AttributeNullException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -0,0 +1,17 @@
namespace CustomComponents.ViewComponents.Exceptions
{
public class HierarchyNullException : Exception
{
public HierarchyNullException()
{
}
public HierarchyNullException(string message) : base(message)
{
}
public HierarchyNullException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -0,0 +1,17 @@
namespace CustomComponents.ViewComponents.Exceptions
{
public class PropertyNullException : Exception
{
public PropertyNullException()
{
}
public PropertyNullException(string message) : base(message)
{
}
public PropertyNullException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -0,0 +1,17 @@
namespace CustomComponents.ViewComponents.Exceptions
{
public class RangeNullException : Exception
{
public RangeNullException()
{
}
public RangeNullException(string message) : base(message)
{
}
public RangeNullException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -0,0 +1,17 @@
namespace CustomComponents.ViewComponents.Exceptions
{
public class WrongRangeException : Exception
{
public WrongRangeException()
{
}
public WrongRangeException(string message) : base(message)
{
}
public WrongRangeException(string message, Exception inner) : base(message, inner)
{
}
}
}

200
COP/WinFormsTestApp/Form1.Designer.cs generated Normal file
View File

@ -0,0 +1,200 @@
namespace WinFormsTestApp
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
customCheckedListBox = new CustomComponents.CustomCheckedListBox();
customNumericUpDown = new CustomComponents.CustomNumericUpDown();
customTreeView = new CustomComponents.CustomTreeView();
labelNumeric = new Label();
labelTree = new Label();
labelList = new Label();
labelEvent = new Label();
labelEventText = new Label();
buttonClear = new Button();
tableWord1 = new CustomComponents.NonViewComponents.TableWord(components);
pieChartWord1 = new CustomComponents.NonViewComponents.PieChartWord(components);
imageWord1 = new CustomComponents.NonViewComponents.ImageWord(components);
buttonTable = new Button();
buttonImage = new Button();
buttonChart = new Button();
SuspendLayout();
//
// customCheckedListBox
//
customCheckedListBox.Location = new Point(545, 118);
customCheckedListBox.Name = "customCheckedListBox";
customCheckedListBox.SelectedValue = "";
customCheckedListBox.Size = new Size(188, 150);
customCheckedListBox.TabIndex = 0;
//
// customNumericUpDown
//
customNumericUpDown.Location = new Point(32, 147);
customNumericUpDown.Max = new decimal(new int[] { 123, 0, 0, 0 });
customNumericUpDown.Min = new decimal(new int[] { 24, 0, 0, int.MinValue });
customNumericUpDown.Name = "customNumericUpDown";
customNumericUpDown.Size = new Size(188, 34);
customNumericUpDown.TabIndex = 1;
customNumericUpDown.Value = new decimal(new int[] { 0, 0, 0, 0 });
//
// customTreeView
//
customTreeView.Hierarchy = null;
customTreeView.Location = new Point(285, 80);
customTreeView.Name = "customTreeView";
customTreeView.Size = new Size(188, 188);
customTreeView.TabIndex = 2;
//
// labelNumeric
//
labelNumeric.AutoSize = true;
labelNumeric.Location = new Point(64, 42);
labelNumeric.Name = "labelNumeric";
labelNumeric.Size = new Size(115, 20);
labelNumeric.TabIndex = 3;
labelNumeric.Text = "CustomNumeric";
//
// labelTree
//
labelTree.AutoSize = true;
labelTree.Location = new Point(333, 42);
labelTree.Name = "labelTree";
labelTree.Size = new Size(87, 20);
labelTree.TabIndex = 4;
labelTree.Text = "CustomTree";
//
// labelList
//
labelList.AutoSize = true;
labelList.Location = new Point(571, 42);
labelList.Name = "labelList";
labelList.Size = new Size(162, 20);
labelList.TabIndex = 5;
labelList.Text = "CustomCheckedListBox";
//
// labelEvent
//
labelEvent.AutoSize = true;
labelEvent.Location = new Point(64, 330);
labelEvent.Name = "labelEvent";
labelEvent.Size = new Size(88, 20);
labelEvent.TabIndex = 6;
labelEvent.Text = "Event Label:";
//
// labelEventText
//
labelEventText.AutoSize = true;
labelEventText.Location = new Point(170, 330);
labelEventText.Name = "labelEventText";
labelEventText.Size = new Size(0, 20);
labelEventText.TabIndex = 7;
//
// buttonClear
//
buttonClear.Location = new Point(591, 274);
buttonClear.Name = "buttonClear";
buttonClear.Size = new Size(94, 29);
buttonClear.TabIndex = 8;
buttonClear.Text = "Clear";
buttonClear.UseVisualStyleBackColor = true;
buttonClear.Click += buttonClear_Click;
//
// buttonTable
//
buttonTable.Location = new Point(285, 326);
buttonTable.Name = "buttonTable";
buttonTable.Size = new Size(158, 29);
buttonTable.TabIndex = 9;
buttonTable.Text = "Создать таблицу";
buttonTable.UseVisualStyleBackColor = true;
buttonTable.Click += buttonTable_Click;
//
// buttonImage
//
buttonImage.Location = new Point(285, 377);
buttonImage.Name = "buttonImage";
buttonImage.Size = new Size(158, 29);
buttonImage.TabIndex = 10;
buttonImage.Text = "Создать фото";
buttonImage.UseVisualStyleBackColor = true;
buttonImage.Click += buttonImage_Click;
//
// buttonChart
//
buttonChart.Location = new Point(285, 423);
buttonChart.Name = "buttonChart";
buttonChart.Size = new Size(158, 29);
buttonChart.TabIndex = 11;
buttonChart.Text = "Создать диаграмму";
buttonChart.UseVisualStyleBackColor = true;
buttonChart.Click += buttonChart_Click;
//
// Form1
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(buttonChart);
Controls.Add(buttonImage);
Controls.Add(buttonTable);
Controls.Add(buttonClear);
Controls.Add(labelEventText);
Controls.Add(labelEvent);
Controls.Add(labelList);
Controls.Add(labelTree);
Controls.Add(labelNumeric);
Controls.Add(customTreeView);
Controls.Add(customNumericUpDown);
Controls.Add(customCheckedListBox);
Name = "Form1";
Text = "Form1";
ResumeLayout(false);
PerformLayout();
}
#endregion
private CustomComponents.CustomCheckedListBox customCheckedListBox;
private CustomComponents.CustomNumericUpDown customNumericUpDown;
private CustomComponents.CustomTreeView customTreeView;
private Label labelNumeric;
private Label labelTree;
private Label labelList;
private Label labelEvent;
private Label labelEventText;
private Button buttonClear;
private CustomComponents.NonViewComponents.TableWord tableWord1;
private CustomComponents.NonViewComponents.PieChartWord pieChartWord1;
private CustomComponents.NonViewComponents.ImageWord imageWord1;
private Button buttonTable;
private Button buttonImage;
private Button buttonChart;
}
}

View File

@ -0,0 +1,120 @@
using CustomComponents;
using CustomComponents.NonViewComponents.Enums;
using CustomComponents.NonViewComponents.Logic;
using CustomComponents.NonViewComponents.SupportClasses;
using WinFormsTestApp.TestClasses;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace WinFormsTestApp
{
public partial class Form1 : Form
{
List<Someone> teachers = new List<Someone>();
List<string> list = new List<string>();
public Form1()
{
list = new List<string>();
list.AddRange(new string[] { "áóëêà", "ìîðîæåííîå", "æâà÷êà" });
Someone teach1 = new Someone("Ïåòðîâ Í.Ñ", "Ãëàâà êàôåäðû", "ÔÈÑÒ", 67);
Someone teach2 = new Someone("Ñåðãååâ Í.Ï", "Çàâ êàôåäðû", "ÔÈÑÒ", 34);
Someone teach3 = new Someone("Âðó÷èí Ï.Ê", "Ïðåïîäàâàòåëü", "ÃÅÎ", 22);
Someone teach4 = new Someone("Ïåòðîâ Í.Ñ", "Àñïèðàíò", "ÃÓÌ", 12);
Someone teach5 = new Someone("Ïåòðîâ Í.Ñ", "Àñïèðàíò", "ÃÓÌ",44);
teachers.Add(teach1);
teachers.Add(teach2);
teachers.Add(teach3);
teachers.Add(teach4);
teachers.Add(teach5);
InitializeComponent();
customNumericUpDown.ValueChanged += onNumericChange!;
customCheckedListBox.SelectChanged += onSelectedChange!;
foreach (string st in list)
{
customCheckedListBox.DataList.Add(st);
}
customCheckedListBox.SelectedValue = "áóëêà";
loadTree();
customTreeView.SelectedTreeNodeID = 2;
}
public void loadTree()
{
customTreeView.Hierarchy = new List<string> { "Position", "Facility", "FIO" };
foreach (Someone teach in teachers)
{
customTreeView.AddNode(teach, "Position");
}
}
public void onNumericChange(object sender, EventArgs e)
{
labelEventText.Text = "Numeric changed value";
}
public void onSelectedChange(object sender, EventArgs e)
{
labelEventText.Text = "Checked List changed selected";
}
private void buttonClear_Click(object sender, EventArgs e)
{
customCheckedListBox.ClearList();
}
private void buttonImage_Click(object sender, EventArgs e)
{
DocImage[] imges = new DocImage[2];
imges[0] = new DocImage();
imges[1] = new DocImage();
imges[0].Path = "C:/repos/test/cat.png";
imges[1].Path = "C:/repos/test/cat2.jpg";
imges[0].Width = 200;
imges[0].Height = 200;
imageWord1.AddImages("C:/repos/test/WordImage.docx","ôîòî", imges);
}
private void buttonChart_Click(object sender, EventArgs e)
{
var series = new List<SeriesData>
{
new() {
SeriesName = "àýýý 1",
ValuesY = new List<double> { 10, 15, 20 },
Color = Color.FromArgb(255, 160, 0)
},
new() {
SeriesName = "àýýý 2",
ValuesY = new List<double> { 45, 35, 15 },
Color = Color.FromArgb(100, 100, 105)
},
new() {
SeriesName = "àýýý 3",
ValuesY = new List<double> { 25, 2, 5 },
Color = Color.FromArgb(255, 255, 0)
}
};
pieChartWord1.CreateDiagramDocument(new PieChartData()
{
FileName = "C:/repos/test/WordChart.docx",
DocumentTitle = "äèàãðàììà",
DiagramTitle = "÷òî-òî",
LegendLayout = PieChartLegendAlign.Bottom,
CategoriesX = new List<string> { "ïåðâàÿ", "âòîðàÿ", "òðåòüÿ" },
SeriesData = series
});
}
private void buttonTable_Click(object sender, EventArgs e)
{
var head = new List<(string, string, string)>
{
("Ëè÷íàÿ èíôîðìàöèÿ", "Ôèî", nameof(Someone.FIO)),
("Ëè÷íàÿ èíôîðìàöèÿ", "Âîçðàñò", nameof(Someone.Age)),
("Äîëæíîñòü", "", nameof(Someone.Position))
};
tableWord1.AddTable<Someone>("C:/repos/test/WordTable.docx", "òàáëèöà", head ,null, teachers);
}
}
}

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="tableWord1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="pieChartWord1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>151, 17</value>
</metadata>
<metadata name="imageWord1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>307, 17</value>
</metadata>
</root>

View File

@ -0,0 +1,17 @@
namespace WinFormsTestApp
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CustomComponents.ViewComponents.Exceptions;
using CustomComponents.ViewComponents.Attributes;
using System.ComponentModel;
namespace WinFormsTestApp.TestClasses
{
public class Someone
{
[AlwaysCreate]
[DisplayName("Фио")]
public string FIO { get; set; }
[DisplayName("Должность")]
public string Position { get; set; }
[DisplayName("Факультет")]
public string Facility { get; set; }
[DisplayName("Возраст")]
public int Age { get; set; }
public Someone(string fio, string pos, string fac, int age)
{
FIO = fio;
Position = pos;
Facility = fac;
Age = age;
}
public Someone() { }
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\CustomComponents\CustomComponents.csproj" />
</ItemGroup>
</Project>