Skip to content

Commit a5e9eb6

Browse files
authored
Merge pull request #222 from Infarh/dev
v0.0.48.3
2 parents 77f08f7 + a1e0319 commit a5e9eb6

77 files changed

Lines changed: 1712 additions & 317 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/copilot-instructions.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Правила для GitHub Copilot
2+
3+
- Всегда отвечай, используя русский язык
4+
- Всегда пиши комментарии в коде на русском языке
5+
6+
## Комментарии
7+
- Короткие пояснительные комментарии располагай в конце той же строки, что и код // кратко по делу
8+
- Старайся избегать тривиальных комментариев
9+
10+
## XML‑документация
11+
- Документируй классы, структуры, делегаты, перечисления и их члены только XML‑комментариями
12+
- Одинарное предложение пиши в одной строке внутри тега и без точки в конце
13+
- Каждый тег XML‑комментария располагай на отдельной строке
14+
- Порядок тегов: `<summary>``<param>``<returns>``<exception>``<remarks>``<example>`
15+
- Для сложных публичных метдов генерируй блок с простым примером использования кода внутри тега `<example>`
16+
17+
Примеры:
18+
- `<summary>Краткое описание сущности</summary>`
19+
- `<param name="Value">Описание параметра</param>`
20+
- `<returns>Описание возвращаемого значения</returns>`
21+
22+
## Синтаксис и минимализм
23+
- При генерации кода используй современные конструкции языка, совместимые с целевыми платформами проекта
24+
- Стремись минимизировать количество фигурных скобок за счёт expression‑bodied членов и switch‑выражений
25+
- Не убирай фигурные скобки в многострочных конструкциях ради читаемости
26+
- Всегда старайся минимизировать размер кода, если не запрошено иное
27+
28+
Разрешённые современные приёмы (когда поддерживается целевой платформой):
29+
- file‑scoped namespace
30+
- expression‑bodied члены
31+
- switch‑выражения и pattern matching
32+
- target‑typed `new`
33+
- collection expressions и инициализаторы коллекций
34+
- `using var` и `await using`
35+
- операторы `??`, `??=`, `is not`, `with`
36+
- упрощение nullable-присвоения `target?.Property = 15;` вместо `if(target is not null) target.Property = 15;`
37+
38+
## Именование
39+
- Локальные переменные: `snake_case`
40+
- Параметры методов: `PascalCase`
41+
- Поля экземпляров: `_PascalCase`
42+
- Статические поля: `__PascalCase`
43+
- Константы: `PascalCase`
44+
- Публичные типы и члены API: `PascalCase`
45+
- Предпочитай английский язык при именовании переменных, методов, классов и прочих сущностей
46+
47+
## Инициализация и объявления
48+
- При инициализации массивов, списков и словарей используй выражения инициализации массивов/коллекций
49+
- При объявлении переменных предпочитай использовать ключевое слово `var` (кроме случаев, когда явный тип заметно повышает понятность)
50+
51+
## Форматирование
52+
- Короткие системные комментарии пиши компактно в одну строку
53+
- Удаляй неиспользуемые `using`, сортируй и группируй директивы `using`
54+
- Разделяй логические блоки пустыми строками по мере необходимости, избегай лишних переносов
55+
56+
## Практики .NET
57+
- Включай `#nullable enable` там, где это поддерживается
58+
- Используй guard‑выражения, например `ArgumentNullException.ThrowIfNull(x)`
59+
- Предпочитай Try‑паттерны для контроля потока вместо исключений
60+
- При генерации метода добавляй в его начале блок проверки входных параметров. Отделяй этот блок пустой строкой от остального тела метода
61+
- При генерации публичных свойств у моделей-представления MVVM (классов, реализующих INotifyPropertyChanged) используй следующий формат (в одну строку):
62+
```csharp
63+
/// <summary>Описание свойства</summary>
64+
public string PropertyName { get; set => Set(ref field, value); }
65+
```
66+
- Для простых лаконичных методов используй expression‑bodied синтаксис, записанный в одну строку.
67+
68+
## Совместимость целей
69+
- В рабочем пространстве используются целевые платформы: `.NET Standard 2.0` и `.NET 10`
70+
- Применяй современные возможности языка и платформы только если они доступны для соответствующей целевой платформы проекта

.github/workflows/publish.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Publish NuGet.org
22

33
on:
44
push:
5-
branches:
5+
branches:
66
- master
7-
paths-ignore:
7+
paths-ignore:
88
- '.github/workflows/**'
99
- '**.md'
1010
- '**.docx'
@@ -18,7 +18,7 @@ env:
1818
jobs:
1919
build:
2020
name: Build
21-
runs-on: windows-latest
21+
runs-on: windows-latest
2222

2323
steps:
2424
- name: Checkout
@@ -29,7 +29,7 @@ jobs:
2929
- name: Setup .NET
3030
uses: actions/setup-dotnet@v4
3131
with:
32-
dotnet-version: 9.0.x
32+
dotnet-version: 10.0.x
3333

3434
- name: Cache NuGet
3535
uses: actions/cache@v4
@@ -69,7 +69,7 @@ jobs:
6969

7070
steps:
7171
- name: Get artifact
72-
uses: actions/download-artifact@v4.1.8
72+
uses: actions/download-artifact@v5
7373
id: download
7474
with:
7575
name: Release
@@ -85,7 +85,7 @@ jobs:
8585

8686
steps:
8787
- name: Get artifact
88-
uses: actions/download-artifact@v4.1.8
88+
uses: actions/download-artifact@v5
8989
id: download
9090
with:
9191
name: Release

.github/workflows/testing.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
- name: Setup .NET
4141
uses: actions/setup-dotnet@v4
4242
with:
43-
dotnet-version: 9.0.x
43+
dotnet-version: 10.0.x
4444

4545
- name: Building
4646
run: |

MathCore.WPF.sln

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Service", ".Service", "{F8
1919
EndProjectSection
2020
EndProject
2121
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{40F619FF-49AE-493A-846A-FE4D455B9BCB}"
22+
ProjectSection(SolutionItems) = preProject
23+
.github\copilot-instructions.md = .github\copilot-instructions.md
24+
EndProjectSection
2225
EndProject
2326
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{C83B7C5C-5536-4BDA-9447-7B9A6393F30E}"
2427
ProjectSection(SolutionItems) = preProject
25-
.github\workflows\publish-github.yml = .github\workflows\publish-github.yml
26-
.github\workflows\publish-nuget.yml = .github\workflows\publish-nuget.yml
28+
.github\workflows\publish.yml = .github\workflows\publish.yml
2729
.github\workflows\testing.yml = .github\workflows\testing.yml
2830
EndProjectSection
2931
EndProject

MathCore.WPF.sln.DotSettings

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@
3131
<s:Boolean x:Key="/Default/UserDictionary/Words/=Viewbox/@EntryIndexedValue">True</s:Boolean>
3232
<s:Boolean x:Key="/Default/UserDictionary/Words/=Xmax/@EntryIndexedValue">True</s:Boolean>
3333
<s:Boolean x:Key="/Default/UserDictionary/Words/=Xmin/@EntryIndexedValue">True</s:Boolean>
34+
<s:Boolean x:Key="/Default/UserDictionary/Words/=_041F_043E_0442_043E_043A_043E_0431_0435_0437_043E_043F_0430_0441_043D_044B_0439/@EntryIndexedValue">True</s:Boolean>
3435
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0430_0432_0442_043E_0437_0430_0432_0435_0440_0448_0435_043D_0438_044F/@EntryIndexedValue">True</s:Boolean>
35-
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0432_0430_043B_0438_0434_0430_0446_0438_0438/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
36+
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0432_0430_043B_0438_0434_0430_0446_0438_0438/@EntryIndexedValue">True</s:Boolean>
37+
<s:Boolean x:Key="/Default/UserDictionary/Words/=_043F_043E_0442_043E_043A_043E_0431_0435_0437_043E_043F_0430_0441_043D_043E_0433_043E/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

MathCore.WPF/AttachedProperties/DataGridEx.cs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,19 @@ public static class DataGridEx
1313
{
1414
#region Attached property DataGrid.UseDataAnnotations : bool - Использовать аннотации данных из пространства имён System.ComponentModel.DataAnnotation
1515

16-
/// <summary>Использовать аннотации данных из пространства имён System.DataAnnotation</summary>
16+
/// <summary>Использовать аннотации данных из пространства имён <see cref="System.ComponentModel"/></summary>
1717
public static readonly DependencyProperty UseDataAnnotationsProperty =
1818
DependencyProperty.RegisterAttached(
1919
"UseDataAnnotations",
2020
typeof(bool),
2121
typeof(DataGridEx),
2222
new(OnUseDataAnnotationsPropertyChanged));
2323

24-
/// <summary>Использовать аннотации данных из пространства имён System.DataAnnotation</summary>
24+
/// <summary>Использовать аннотации данных из пространства имён <see cref="System.ComponentModel.DataAnnotations"/></summary>
2525
[AttachedPropertyBrowsableForType(typeof(DataGrid))]
2626
public static void SetUseDataAnnotations(DependencyObject D, bool value) => D.SetValue(UseDataAnnotationsProperty, value);
2727

28-
/// <summary>Использовать аннотации данных из пространства имён System.DataAnnotation</summary>
28+
/// <summary>Использовать аннотации данных из пространства имён <see cref="System.ComponentModel.DataAnnotations"/></summary>
2929
public static bool GetUseDataAnnotations(DependencyObject D) => (bool)D.GetValue(UseDataAnnotationsProperty);
3030

3131
private static void OnUseDataAnnotationsPropertyChanged(DependencyObject D, DependencyPropertyChangedEventArgs E)
@@ -59,26 +59,15 @@ private static void OnDataGridGeneratingColumn(object? Sender, DataGridAutoGener
5959

6060
var column = E.Column;
6161

62-
//if (property.PropertyType == typeof(DateTime))
63-
//{
64-
// E.Column = new DataGridTemplateColumn
65-
// {
66-
// HeaderTemplate = column.HeaderTemplate,
67-
// Header = column.Header,
68-
// CellTemplate = new DataTemplate(item_type) { }
69-
// };
70-
// column = E.Column;
71-
//}
72-
7362
var display_attribute = property.GetCustomAttribute<DisplayAttribute>();
7463

75-
if(display_attribute?.GetAutoGenerateField() == false)
64+
if (display_attribute?.GetAutoGenerateField() == false)
7665
{
7766
E.Cancel = true;
7867
return;
7968
}
8069

81-
if((display_attribute?.Name ?? property.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName) is { } name)
70+
if ((display_attribute?.Name ?? property.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName) is { } name)
8271
column.Header = name;
8372

8473
if (display_attribute?.Name is { } description)
@@ -94,12 +83,12 @@ private static void OnDataGridGeneratingColumn(object? Sender, DataGridAutoGener
9483

9584
if (property.GetCustomAttribute<DisplayFormatAttribute>() is { } format_attribute)
9685
{
97-
var text_column = column as DataGridTextColumn;
86+
var text_column = column as DataGridTextColumn;
9887
var value_format = format_attribute.DataFormatString;
9988
if (value_format != null && text_column != null)
10089
{
10190
var binding = (Binding)text_column.Binding;
102-
binding.StringFormat = value_format;
91+
binding.StringFormat = value_format;
10392
binding.ConverterCulture = Thread.CurrentThread.CurrentUICulture;
10493
}
10594

@@ -112,17 +101,17 @@ private static void OnDataGridGeneratingColumn(object? Sender, DataGridAutoGener
112101
column.IsReadOnly = column_readonly;
113102

114103
if (property.GetCustomAttribute<ColumnWidthAttribute>() is
115-
{
116-
Width : var col_width,
117-
Auto : var col_auto,
118-
Adaptive: var col_adaptive
119-
})
104+
{
105+
Width: var col_width,
106+
Auto: var col_auto,
107+
Adaptive: var col_adaptive
108+
})
120109
column.Width = (col_width, col_auto, col_adaptive) switch
121110
{
122111
(not double.NaN and var width, false, false) => new DataGridLength(width),
123-
(var width, false, true) => new DataGridLength(width, DataGridLengthUnitType.Star),
124-
(var width, true, _) => new DataGridLength(width, DataGridLengthUnitType.Auto),
125-
_ => new DataGridLength()
112+
(var width, false, true) => new DataGridLength(width, DataGridLengthUnitType.Star),
113+
(var width, true, _) => new DataGridLength(width, DataGridLengthUnitType.Auto),
114+
_ => new DataGridLength()
126115
};
127116
}
128117

MathCore.WPF/AttachedProperties/UI.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public static class UI
1212
"InputBinding",
1313
typeof(InputBinding),
1414
typeof(UI),
15-
new(default(InputBinding), OnInputBindingChanged));
15+
new(null, OnInputBindingChanged));
1616

1717
/// <summary>Обработчик события изменения значения свойства <see cref="InputBindingProperty"/></summary>
1818
/// <param name="D">Элемент, с которым ассоциирована коллекция горячих клавиш</param>
@@ -43,14 +43,14 @@ public static class UI
4343
/// <summary>Глобальные горячие клавиши</summary>
4444
public static GlobalHotKeysCollection GetHotKeys(DependencyObject element)
4545
{
46-
if (element.GetValue(HotKeysProperty) is GlobalHotKeysCollection collection)
46+
if (element.GetValue(HotKeysProperty) is GlobalHotKeysCollection collection)
4747
return collection;
4848

4949
collection = [];
5050
if (element is FrameworkElement framework_element)
5151
framework_element.Unloaded += (e, _) =>
5252
{
53-
if(((DependencyObject)e).GetValue(HotKeysProperty) is GlobalHotKeysCollection keys)
53+
if (((DependencyObject)e).GetValue(HotKeysProperty) is GlobalHotKeysCollection keys)
5454
keys.Dispose();
5555
};
5656
SetHotKeys(element, collection);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#if !NET5_0_OR_GREATER
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace System.Diagnostics.CodeAnalysis;
9+
10+
/// <summary>Specifies that <see langword="null" /> is allowed as an input even if the corresponding type disallows it.</summary>
11+
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
12+
public sealed class AllowNullAttribute : Attribute
13+
{
14+
}
15+
16+
/// <summary>Specifies that an output may be <see langword="null" /> even if the corresponding type disallows it.</summary>
17+
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
18+
public sealed class MaybeNullAttribute : Attribute
19+
{
20+
}
21+
22+
#endif

MathCore.WPF/CollectionSelector.cs

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,50 +13,33 @@ public class CollectionSelector<T>(bool SelectFirstItem = true) : ViewModel
1313
{
1414
#region Items : IEnumerable<T> - Коллекция
1515

16-
/// <summary>Коллекция</summary>
17-
private IEnumerable<T>? _Items;
18-
1916
/// <summary>Коллекция</summary>
2017
public IEnumerable<T>? Items
2118
{
22-
get => _Items;
19+
get;
2320
set
2421
{
25-
if (Set(ref _Items, value))
22+
if (Set(ref field, value))
2623
SelectedItem = value switch
2724
{
28-
T[] { Length : > 0 } array => array[0],
29-
List<T> { Count : > 0 } list => list[0],
30-
LinkedList<T> { First.Value : { } first_value } => first_value,
31-
ObservableCollection<T> { Count: > 0 } collection => collection[0],
32-
IList<T> { Count : > 0 } list => list[0],
33-
{ } items => items.FirstOrDefault(),
34-
_ => default
25+
T[] { Length: > 0 } array => array[0],
26+
List<T> { Count: > 0 } list => list[0],
27+
LinkedList<T> { First.Value: { } first_value } => first_value,
28+
ObservableCollection<T> { Count: > 0 } collection => collection[0],
29+
IList<T> { Count: > 0 } list => list[0],
30+
{ } items => items.FirstOrDefault(),
31+
_ => default
3532
};
3633
}
3734
}
3835

3936
#endregion
4037

41-
#region SelectedItem : T - Выбранный элемент
42-
4338
/// <summary>Выбранный элемент</summary>
44-
private T? _SelectedItem;
45-
46-
/// <summary>Выбранный элемент</summary>
47-
public T? SelectedItem { get => _SelectedItem; set => Set(ref _SelectedItem, value); }
48-
49-
#endregion
50-
51-
#region SelectFirstItem : bool - Выбирать первый элемент для нового значения коллекции
52-
53-
/// <summary>Выбирать первый элемент для нового значения коллекции</summary>
54-
private bool _SelectFirstItem = SelectFirstItem;
39+
public T? SelectedItem { get; set => Set(ref field, value); }
5540

5641
/// <summary>Выбирать первый элемент для нового значения коллекции</summary>
57-
public bool SelectFirstItem { get => _SelectFirstItem; set => Set(ref _SelectFirstItem, value); }
58-
59-
#endregion
42+
public bool SelectFirstItem { get; set => Set(ref field, value); } = SelectFirstItem;
6043

6144
public CollectionSelector(IEnumerable<T> Items, bool SelectFirstItem = true) : this(SelectFirstItem) => this.Items = Items;
6245

MathCore.WPF/CollectionViewShaper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace MathCore.WPF;
88

9-
/// <summary> </summary>
9+
/// <summary>Формирует fluent-api для задания представления коллекции WPF с помощью LINQ-подобного синтаксиса</summary>
1010
/// <remarks>
1111
/// <code>
1212
/// // Collection to which the view is bound
@@ -128,7 +128,7 @@ public CollectionViewShaper<T> GroupBy<TKey>(Expression<Func<T, TKey>> selector)
128128
private static string GetPropertyPath(Expression expression)
129129
{
130130
var names = new Stack<string>();
131-
var expr = expression;
131+
var expr = expression;
132132
while (expr is not null and not ParameterExpression and not ConstantExpression)
133133
{
134134
if (expr is not MemberExpression member)

0 commit comments

Comments
 (0)