Compare commits

...

13 Commits
main ... lab2-3

72 changed files with 4368 additions and 79 deletions

View File

@ -3,9 +3,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.11.35222.181 VisualStudioVersion = 17.11.35222.181
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RodionovLibrary", "RodionovLibrary\RodionovLibrary.csproj", "{F586414D-01E1-499C-A77B-C6A4B0882B0E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RodionovLibrary", "RodionovLibrary\RodionovLibrary.csproj", "{F586414D-01E1-499C-A77B-C6A4B0882B0E}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinForms", "WinForms\WinForms.csproj", "{E160EBCF-4BD1-4049-ADD6-597332133952}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinForms", "WinForms\WinForms.csproj", "{E160EBCF-4BD1-4049-ADD6-597332133952}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PortalAccountsContracts", "PortalAccountsContracts\PortalAccountsContracts.csproj", "{F18747FB-607B-42E4-AA8E-86A7E2FFBD28}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PortalAccountsDataModels", "PortalAccountsDataModels\PortalAccountsDataModels.csproj", "{4DFB6049-FCE4-42F3-B611-BAEE5156EA9C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PortalAccountsBusinessLogic", "PortalAccountsBusinessLogic\PortalAccountsBusinessLogic.csproj", "{06D98752-0805-4CE4-AE5A-0EC14694D7D9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PortalAccountsDatabaseImplement", "PortalAccountsDatabaseImplement\PortalAccountsDatabaseImplement.csproj", "{0D3E5B70-5816-4AF6-AA94-95EA34EEC9FE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PortalAccountsView", "PortalAccountsView\PortalAccountsView.csproj", "{0304D12E-0F97-4C82-BB88-4E4784DEC81C}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -21,6 +31,26 @@ Global
{E160EBCF-4BD1-4049-ADD6-597332133952}.Debug|Any CPU.Build.0 = Debug|Any CPU {E160EBCF-4BD1-4049-ADD6-597332133952}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E160EBCF-4BD1-4049-ADD6-597332133952}.Release|Any CPU.ActiveCfg = Release|Any CPU {E160EBCF-4BD1-4049-ADD6-597332133952}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E160EBCF-4BD1-4049-ADD6-597332133952}.Release|Any CPU.Build.0 = Release|Any CPU {E160EBCF-4BD1-4049-ADD6-597332133952}.Release|Any CPU.Build.0 = Release|Any CPU
{F18747FB-607B-42E4-AA8E-86A7E2FFBD28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F18747FB-607B-42E4-AA8E-86A7E2FFBD28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F18747FB-607B-42E4-AA8E-86A7E2FFBD28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F18747FB-607B-42E4-AA8E-86A7E2FFBD28}.Release|Any CPU.Build.0 = Release|Any CPU
{4DFB6049-FCE4-42F3-B611-BAEE5156EA9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DFB6049-FCE4-42F3-B611-BAEE5156EA9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DFB6049-FCE4-42F3-B611-BAEE5156EA9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DFB6049-FCE4-42F3-B611-BAEE5156EA9C}.Release|Any CPU.Build.0 = Release|Any CPU
{06D98752-0805-4CE4-AE5A-0EC14694D7D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06D98752-0805-4CE4-AE5A-0EC14694D7D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06D98752-0805-4CE4-AE5A-0EC14694D7D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06D98752-0805-4CE4-AE5A-0EC14694D7D9}.Release|Any CPU.Build.0 = Release|Any CPU
{0D3E5B70-5816-4AF6-AA94-95EA34EEC9FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D3E5B70-5816-4AF6-AA94-95EA34EEC9FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D3E5B70-5816-4AF6-AA94-95EA34EEC9FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D3E5B70-5816-4AF6-AA94-95EA34EEC9FE}.Release|Any CPU.Build.0 = Release|Any CPU
{0304D12E-0F97-4C82-BB88-4E4784DEC81C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0304D12E-0F97-4C82-BB88-4E4784DEC81C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0304D12E-0F97-4C82-BB88-4E4784DEC81C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0304D12E-0F97-4C82-BB88-4E4784DEC81C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -0,0 +1,78 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsBusinessLogic.BusinessLogics
{
public class AccountLogic : IAccountLogic
{
private readonly IAccountStorage _accountStorage;
public AccountLogic(IAccountStorage AccountStorage)
{
_accountStorage = AccountStorage;
}
public List<AccountViewModel>? ReadList(AccountSearchModel? model)
{
return model == null ? _accountStorage.GetFullList() : _accountStorage.GetFilteredList(model);
}
public AccountViewModel? ReadElement(AccountSearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
return _accountStorage.GetElement(model);
}
public bool Create(AccountBindingModel model)
{
CheckModel(model);
return _accountStorage.Insert(model) != null;
}
public bool Update(AccountBindingModel model)
{
CheckModel(model);
return _accountStorage.Update(model) != null;
}
public bool Delete(AccountBindingModel model)
{
CheckModel(model, false);
return _accountStorage.Delete(model) != null;
}
private void CheckModel(AccountBindingModel model, bool withParams = true)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
if (!withParams)
{
return;
}
if (string.IsNullOrEmpty(model.Login))
{
throw new ArgumentNullException("Нет логина у аккаунта", nameof(model.Login));
}
if (model.RoleId <= 0)
{
throw new ArgumentNullException("Некорректный идентификатор роли", nameof(model.RoleId));
}
var element = _accountStorage.GetElement(new AccountSearchModel
{
Login = model.Login
});
if (element != null && element.Id != model.Id)
{
throw new InvalidOperationException("Аккаунт с таким логином уже есть");
}
}
}
}

View File

@ -0,0 +1,74 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsBusinessLogic.BusinessLogics
{
public class RoleLogic : IRoleLogic
{
private readonly IRoleStorage _roleStorage;
public RoleLogic(IRoleStorage RoleStorage)
{
_roleStorage = RoleStorage;
}
public List<RoleViewModel>? ReadList(RoleSearchModel? model)
{
return model == null ? _roleStorage.GetFullList() : _roleStorage.GetFilteredList(model);
}
public RoleViewModel? ReadElement(RoleSearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
return _roleStorage.GetElement(model);
}
public bool Create(RoleBindingModel model)
{
CheckModel(model);
return _roleStorage.Insert(model) != null;
}
public bool Update(RoleBindingModel model)
{
CheckModel(model);
return _roleStorage.Update(model) != null;
}
public bool Delete(RoleBindingModel model)
{
CheckModel(model, false);
return _roleStorage.Delete(model) != null;
}
private void CheckModel(RoleBindingModel model, bool withParams = true)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
if (!withParams)
{
return;
}
if (string.IsNullOrEmpty(model.Name))
{
throw new ArgumentNullException("Нет названия роли", nameof(model.Name));
}
var element = _roleStorage.GetElement(new RoleSearchModel
{
Name = model.Name
});
if (element != null && element.Id != model.Id)
{
throw new InvalidOperationException("Роль с таким названием уже есть");
}
}
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsContracts\PortalAccountsContracts.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,17 @@
using PortalAccountsDataModels.Models;
namespace PortalAccountsContracts.BindingModels
{
public class AccountBindingModel : IAccountModel
{
public int Id { get; set; }
public string Login { get; set; } = string.Empty;
public string? Warnings { get; set; }
public int RoleId { get; set; }
public double? Rating { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using PortalAccountsDataModels.Models;
namespace PortalAccountsContracts.BindingModels
{
public class RoleBindingModel : IRoleModel
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,19 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.BusinessLogicsContracts
{
public interface IAccountLogic
{
List<AccountViewModel>? ReadList(AccountSearchModel? model);
AccountViewModel? ReadElement(AccountSearchModel model);
bool Create(AccountBindingModel model);
bool Update(AccountBindingModel model);
bool Delete(AccountBindingModel model);
}
}

View File

@ -0,0 +1,19 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.BusinessLogicsContracts
{
public interface IRoleLogic
{
List<RoleViewModel>? ReadList(RoleSearchModel? model);
RoleViewModel? ReadElement(RoleSearchModel model);
bool Create(RoleBindingModel model);
bool Update(RoleBindingModel model);
bool Delete(RoleBindingModel model);
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsDataModels\PortalAccountsDataModels.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,11 @@
namespace PortalAccountsContracts.SearchModels
{
public class AccountSearchModel
{
public int? Id { get; set; }
public string? Login { get; set; }
public int? RoleId { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace PortalAccountsContracts.SearchModels
{
public class RoleSearchModel
{
public int? Id { get; set; }
public string? Name { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.StoragesContracts
{
public interface IAccountStorage
{
List<AccountViewModel> GetFullList();
List<AccountViewModel> GetFilteredList(AccountSearchModel model);
AccountViewModel? GetElement(AccountSearchModel model);
AccountViewModel? Insert(AccountBindingModel model);
AccountViewModel? Update(AccountBindingModel model);
AccountViewModel? Delete(AccountBindingModel model);
}
}

View File

@ -0,0 +1,21 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.StoragesContracts
{
public interface IRoleStorage
{
List<RoleViewModel> GetFullList();
List<RoleViewModel> GetFilteredList(RoleSearchModel model);
RoleViewModel? GetElement(RoleSearchModel model);
RoleViewModel? Insert(RoleBindingModel model);
RoleViewModel? Update(RoleBindingModel model);
RoleViewModel? Delete(RoleBindingModel model);
}
}

View File

@ -0,0 +1,26 @@
using PortalAccountsDataModels.Models;
using System.ComponentModel;
namespace PortalAccountsContracts.ViewModels
{
public class AccountViewModel : IAccountModel
{
public int Id { get; set; }
[DisplayName("Логин")]
public string Login { get; set; } = string.Empty;
[DisplayName("Предупреждения")]
public string? Warnings { get; set; }
public int RoleId { get; set; }
[DisplayName("Роль")]
public string RoleName { get; set; } = string.Empty;
[DisplayName("Рейтинг")]
public double? Rating { get; set; }
public string OutputRating { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,13 @@
using PortalAccountsDataModels.Models;
using System.ComponentModel;
namespace PortalAccountsContracts.ViewModels
{
public class RoleViewModel : IRoleModel
{
public int Id { get; set; }
[DisplayName("Название роли")]
public string Name { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,7 @@
namespace PortalAccountsDataModels
{
public interface IId
{
int Id { get; }
}
}

View File

@ -0,0 +1,13 @@
namespace PortalAccountsDataModels.Models
{
public interface IAccountModel : IId
{
string Login { get; }
string? Warnings { get; }
int RoleId { get; }
double? Rating { get; }
}
}

View File

@ -0,0 +1,7 @@
namespace PortalAccountsDataModels.Models
{
public interface IRoleModel : IId
{
string Name { get; }
}
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,98 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
namespace PortalAccountsDatabaseImplement.Implements
{
public class AccountStorage : IAccountStorage
{
public List<AccountViewModel> GetFullList()
{
using var context = new PortalAccountsDatabase();
return context.Accounts
.Include(x => x.Role)
.Select(x => x.GetViewModel)
.ToList();
}
public List<AccountViewModel> GetFilteredList(AccountSearchModel model)
{
using var context = new PortalAccountsDatabase();
if (model.RoleId.HasValue)
{
return context.Accounts
.Include(x => x.Role)
.Where(x => x.RoleId == model.RoleId)
.Select(x => x.GetViewModel)
.ToList();
}
return new();
}
public AccountViewModel? GetElement(AccountSearchModel model)
{
if (string.IsNullOrEmpty(model.Login) && !model.Id.HasValue)
{
return null;
}
using var context = new PortalAccountsDatabase();
return context.Accounts
.Include(x => x.Role)
.FirstOrDefault(x => !string.IsNullOrEmpty(model.Login) && x.Login == model.Login ||
model.Id.HasValue && x.Id == model.Id)
?.GetViewModel;
}
public AccountViewModel? Insert(AccountBindingModel model)
{
var newAccount = Account.Create(model);
if (newAccount == null)
{
return null;
}
using var context = new PortalAccountsDatabase();
context.Accounts.Add(newAccount);
context.SaveChanges();
return context.Accounts
.Include(x => x.Role)
.FirstOrDefault(x => x.Id == newAccount.Id)
?.GetViewModel;
}
public AccountViewModel? Update(AccountBindingModel model)
{
using var context = new PortalAccountsDatabase();
var account = context.Accounts.FirstOrDefault(x => x.Id == model.Id);
if (account == null)
{
return null;
}
account.Update(model);
context.SaveChanges();
return context.Accounts
.Include(x => x.Role)
.FirstOrDefault(x => x.Id == model.Id)
?.GetViewModel;
}
public AccountViewModel? Delete(AccountBindingModel model)
{
using var context = new PortalAccountsDatabase();
var element = context.Accounts.FirstOrDefault(rec => rec.Id == model.Id);
if (element != null)
{
var deletedElement = context.Accounts
.Include(x => x.Role)
.FirstOrDefault(x => x.Id == model.Id)
?.GetViewModel;
context.Accounts.Remove(element);
context.SaveChanges();
return deletedElement;
}
return null;
}
}
}

View File

@ -0,0 +1,84 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDatabaseImplement.Models;
namespace PortalAccountsDatabaseImplement.Implements
{
public class RoleStorage : IRoleStorage
{
public List<RoleViewModel> GetFullList()
{
using var context = new PortalAccountsDatabase();
return context.Roles
.Select(x => x.GetViewModel)
.ToList();
}
public List<RoleViewModel> GetFilteredList(RoleSearchModel model)
{
if (string.IsNullOrEmpty(model.Name))
{
return new();
}
using var context = new PortalAccountsDatabase();
return context.Roles
.Where(x => x.Name.Contains(model.Name))
.Select(x => x.GetViewModel)
.ToList();
}
public RoleViewModel? GetElement(RoleSearchModel model)
{
if (string.IsNullOrEmpty(model.Name) && !model.Id.HasValue)
{
return null;
}
using var context = new PortalAccountsDatabase();
return context.Roles
.FirstOrDefault(x => !string.IsNullOrEmpty(model.Name) && x.Name == model.Name ||
model.Id.HasValue && x.Id == model.Id)
?.GetViewModel;
}
public RoleViewModel? Insert(RoleBindingModel model)
{
var newRole = Role.Create(model);
if (newRole == null)
{
return null;
}
using var context = new PortalAccountsDatabase();
context.Roles.Add(newRole);
context.SaveChanges();
return newRole.GetViewModel;
}
public RoleViewModel? Update(RoleBindingModel model)
{
using var context = new PortalAccountsDatabase();
var role = context.Roles.FirstOrDefault(x => x.Id == model.Id);
if (role == null)
{
return null;
}
role.Update(model);
context.SaveChanges();
return role.GetViewModel;
}
public RoleViewModel? Delete(RoleBindingModel model)
{
using var context = new PortalAccountsDatabase();
var element = context.Roles.FirstOrDefault(rec => rec.Id == model.Id);
if (element != null)
{
context.Roles.Remove(element);
context.SaveChanges();
return element.GetViewModel;
}
return null;
}
}
}

View File

@ -0,0 +1,91 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using PortalAccountsDatabaseImplement;
#nullable disable
namespace PortalAccountsDatabaseImplement.Migrations
{
[DbContext(typeof(PortalAccountsDatabase))]
[Migration("20241022165136_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.Property<double?>("Rating")
.HasColumnType("double precision");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.Property<string>("Warnings")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("Accounts");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Roles");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.HasOne("PortalAccountsDatabaseImplement.Models.Role", "Role")
.WithMany("Accounts")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Role");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Role", b =>
{
b.Navigation("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,65 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace PortalAccountsDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Roles",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Roles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Accounts",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Login = table.Column<string>(type: "text", nullable: false),
Warnings = table.Column<string>(type: "text", nullable: true),
RoleId = table.Column<int>(type: "integer", nullable: false),
Rating = table.Column<double>(type: "double precision", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Accounts", x => x.Id);
table.ForeignKey(
name: "FK_Accounts_Roles_RoleId",
column: x => x.RoleId,
principalTable: "Roles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Accounts_RoleId",
table: "Accounts",
column: "RoleId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Accounts");
migrationBuilder.DropTable(
name: "Roles");
}
}
}

View File

@ -0,0 +1,88 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using PortalAccountsDatabaseImplement;
#nullable disable
namespace PortalAccountsDatabaseImplement.Migrations
{
[DbContext(typeof(PortalAccountsDatabase))]
partial class PortalAccountsDatabaseModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.Property<double?>("Rating")
.HasColumnType("double precision");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.Property<string>("Warnings")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("Accounts");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Roles");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.HasOne("PortalAccountsDatabaseImplement.Models.Role", "Role")
.WithMany("Accounts")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Role");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Role", b =>
{
b.Navigation("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,62 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDataModels.Models;
using System.ComponentModel.DataAnnotations;
namespace PortalAccountsDatabaseImplement.Models
{
public class Account : IAccountModel
{
public int Id { get; private set; }
[Required]
public string Login { get; set; } = string.Empty;
public string? Warnings { get; set; }
[Required]
public int RoleId { get; set; }
public double? Rating { get; set; }
public virtual Role Role { get; set; }
public static Account? Create(AccountBindingModel? model)
{
if (model == null)
{
return null;
}
return new Account()
{
Id = model.Id,
Login = model.Login,
Warnings = model.Warnings,
RoleId = model.RoleId,
Rating = model.Rating
};
}
public void Update(AccountBindingModel? model)
{
if (model == null)
{
return;
}
Login = model.Login;
Warnings = model.Warnings;
RoleId = model.RoleId;
Rating = model.Rating;
}
public AccountViewModel GetViewModel => new()
{
Id = Id,
Login = Login,
Warnings = Warnings,
RoleId = RoleId,
RoleName = Role.Name ?? string.Empty,
Rating = Rating
};
}
}

View File

@ -0,0 +1,48 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDataModels.Models;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PortalAccountsDatabaseImplement.Models
{
public class Role : IRoleModel
{
public int Id { get; private set; }
[Required]
public string Name { get; private set; } = string.Empty;
[ForeignKey("RoleId")]
public virtual List<Account> Accounts { get; set; } = new();
public static Role? Create(RoleBindingModel model)
{
if (model == null)
{
return null;
}
return new Role()
{
Id = model.Id,
Name = model.Name
};
}
public void Update(RoleBindingModel model)
{
if (model == null)
{
return;
}
Name = model.Name;
}
public RoleViewModel GetViewModel => new()
{
Id = Id,
Name = Name
};
}
}

View File

@ -0,0 +1,23 @@
using PortalAccountsDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
namespace PortalAccountsDatabaseImplement
{
public class PortalAccountsDatabase : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured == false)
{
optionsBuilder.UseNpgsql(@"Host=localhost;Database=portal_accounts_database;Username=postgres;Password=bythop423956");
}
base.OnConfiguring(optionsBuilder);
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
public virtual DbSet<Account> Accounts { set; get; }
public virtual DbSet<Role> Roles { set; get; }
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsContracts\PortalAccountsContracts.csproj" />
<ProjectReference Include="..\PortalAccountsDataModels\PortalAccountsDataModels.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,173 @@
namespace PortalAccountsView
{
partial class FormAccount
{
/// <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()
{
controlInputRating = new ControlsLibraryNet60.Input.ControlInputNullableDouble();
textBoxLogin = new TextBox();
textBoxWarnings = new TextBox();
buttonSave = new Button();
labelLogin = new Label();
labelWarnings = new Label();
labelRating = new Label();
labelRole = new Label();
comboBoxControlRole = new RodionovLibrary.VisualComponents.ComboBoxControl();
buttonCancel = new Button();
SuspendLayout();
//
// controlInputRating
//
controlInputRating.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
controlInputRating.Location = new Point(9, 263);
controlInputRating.Margin = new Padding(5, 8, 5, 8);
controlInputRating.Name = "controlInputRating";
controlInputRating.Size = new Size(376, 36);
controlInputRating.TabIndex = 0;
controlInputRating.Value = null;
//
// textBoxLogin
//
textBoxLogin.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
textBoxLogin.Location = new Point(17, 115);
textBoxLogin.Name = "textBoxLogin";
textBoxLogin.Size = new Size(369, 27);
textBoxLogin.TabIndex = 2;
textBoxLogin.TextChanged += TextBoxLogin_TextChanged;
//
// textBoxWarnings
//
textBoxWarnings.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
textBoxWarnings.Location = new Point(17, 191);
textBoxWarnings.Name = "textBoxWarnings";
textBoxWarnings.Size = new Size(369, 27);
textBoxWarnings.TabIndex = 3;
textBoxWarnings.TextChanged += TextBoxWarnings_TextChanged;
//
// buttonSave
//
buttonSave.Location = new Point(29, 309);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(105, 36);
buttonSave.TabIndex = 8;
buttonSave.Text = "Сохранить";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += ButtonSave_Click;
//
// labelLogin
//
labelLogin.AutoSize = true;
labelLogin.Location = new Point(17, 85);
labelLogin.Name = "labelLogin";
labelLogin.Size = new Size(52, 20);
labelLogin.TabIndex = 4;
labelLogin.Text = "Логин";
//
// labelWarnings
//
labelWarnings.AutoSize = true;
labelWarnings.Location = new Point(17, 160);
labelWarnings.Name = "labelWarnings";
labelWarnings.Size = new Size(131, 20);
labelWarnings.TabIndex = 5;
labelWarnings.Text = "Предупреждения";
//
// labelRating
//
labelRating.AutoSize = true;
labelRating.Location = new Point(22, 232);
labelRating.Name = "labelRating";
labelRating.Size = new Size(64, 20);
labelRating.TabIndex = 6;
labelRating.Text = "Рейтинг";
//
// labelRole
//
labelRole.AutoSize = true;
labelRole.Location = new Point(21, 16);
labelRole.Name = "labelRole";
labelRole.Size = new Size(42, 20);
labelRole.TabIndex = 7;
labelRole.Text = "Роль";
//
// comboBoxControlRole
//
comboBoxControlRole.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
comboBoxControlRole.Location = new Point(17, 44);
comboBoxControlRole.Margin = new Padding(3, 4, 3, 4);
comboBoxControlRole.Name = "comboBoxControlRole";
comboBoxControlRole.SelectedValue = "";
comboBoxControlRole.Size = new Size(369, 35);
comboBoxControlRole.TabIndex = 8;
//
// buttonCancel
//
buttonCancel.Location = new Point(168, 309);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(105, 36);
buttonCancel.TabIndex = 9;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += ButtonCancel_Click;
//
// FormAccount
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(408, 363);
Controls.Add(buttonCancel);
Controls.Add(comboBoxControlRole);
Controls.Add(labelRole);
Controls.Add(labelRating);
Controls.Add(labelWarnings);
Controls.Add(labelLogin);
Controls.Add(buttonSave);
Controls.Add(textBoxWarnings);
Controls.Add(textBoxLogin);
Controls.Add(controlInputRating);
Name = "FormAccount";
Text = "Аккаунт";
FormClosing += FormAccount_FormClosing;
Load += FormAccount_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private ControlsLibraryNet60.Input.ControlInputNullableDouble controlInputRating;
private TextBox textBoxLogin;
private TextBox textBoxWarnings;
private Button buttonSave;
private Label labelLogin;
private Label labelWarnings;
private Label labelRating;
private Label labelRole;
private RodionovLibrary.VisualComponents.ComboBoxControl comboBoxControlRole;
private Button buttonCancel;
}
}

View File

@ -0,0 +1,140 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
using System.Data;
namespace PortalAccountsView
{
public partial class FormAccount : Form
{
private int? _id;
private bool _isModified = false;
private readonly IAccountLogic _logic;
private readonly IRoleLogic _roleLogic;
private List<RoleViewModel> _roles;
public int Id { set { _id = value; } }
public FormAccount(IAccountLogic logic, IRoleLogic roleLogic)
{
InitializeComponent();
_logic = logic;
_roleLogic = roleLogic;
_roles = new List<RoleViewModel>();
comboBoxControlRole.ValueChanged += (_, _) => _isModified = true;
controlInputRating.ElementChanged += (_, _) => _isModified = true;
}
private void FormAccount_Load(object sender, EventArgs e)
{
_roles = _roleLogic.ReadList(null) ?? throw new Exception("Не удалось получить список ролей");
comboBoxControlRole.AddItems(_roles.Select(x => x.Name).ToList());
if (_id.HasValue)
{
try
{
var account = _logic.ReadElement(new AccountSearchModel { Id = _id.Value });
if (account != null)
{
textBoxLogin.Text = account.Login;
textBoxWarnings.Text = account.Warnings;
controlInputRating.Value = account.Rating;
comboBoxControlRole.SelectedValue = account.RoleName;
_isModified = false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void ButtonCancel_Click(object sender, EventArgs e)
{
if (_isModified)
{
var result = MessageBox.Show(
"У вас есть несохранённые изменения. Вы действительно хотите закрыть форму?",
"Предупреждение",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning
);
if (result == DialogResult.No)
return;
}
DialogResult = DialogResult.Cancel;
Close();
}
private void ButtonSave_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBoxLogin.Text))
{
MessageBox.Show("Заполните логин", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (string.IsNullOrEmpty(comboBoxControlRole.SelectedValue))
{
MessageBox.Show("Выберите роль", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
try
{
var model = new AccountBindingModel
{
Id = _id ?? 0,
Login = textBoxLogin.Text,
Warnings = textBoxWarnings.Text,
Rating = controlInputRating.Value,
RoleId = _roles.First(x => x.Name == comboBoxControlRole.SelectedValue).Id,
};
var operationResult = _id.HasValue ? _logic.Update(model) : _logic.Create(model);
if (!operationResult)
{
throw new Exception("Ошибка при сохранении");
}
MessageBox.Show("Сохранение прошло успешно", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information);
DialogResult = DialogResult.OK;
Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void TextBoxLogin_TextChanged(object sender, EventArgs e)
{
_isModified = true;
}
private void TextBoxWarnings_TextChanged(object sender, EventArgs e)
{
_isModified = true;
}
private void FormAccount_FormClosing(object sender, FormClosingEventArgs e)
{
if (!_isModified || DialogResult == DialogResult.OK)
return;
var result = MessageBox.Show(
"У вас есть несохранённые изменения. Вы действительно хотите закрыть форму?",
"Предупреждение",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning
);
if (result == DialogResult.No)
e.Cancel = true;
}
}
}

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
Version 2.0 Version 2.0
The primary goals of this format is to allow a simple XML format The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes various data types are done through the TypeConverter classes
associated with the data types. associated with the data types.
Example: Example:
... ado.net/XML headers & schema ... ... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader> <resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader> <resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment> <comment>This is a comment</comment>
</data> </data>
There are any number of "resheader" rows that contain simple There are any number of "resheader" rows that contain simple
name/value pairs. name/value pairs.
Each data row contains a name, and value. The row also contains a Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture. text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the Classes that don't support this are serialized and stored with the
mimetype set. mimetype set.
The mimetype is used for serialized objects, and tells the The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly: extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below. read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64 mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64 mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64 mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
--> -->

View File

@ -0,0 +1,179 @@
namespace PortalAccountsView
{
partial class FormMain
{
/// <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();
controlDataTreeTable = new ControlsLibraryNet60.Data.ControlDataTreeTable();
wordLongTextComponent = new RodionovLibrary.NonVisualComponents.WordLongTextComponent(components);
componentDocumentWithTableMultiHeaderPdf = new ComponentsLibraryNet60.DocumentWithTable.ComponentDocumentWithTableMultiHeaderPdf(components);
componentDocumentWithChartPieExcel = new ComponentsLibraryNet60.DocumentWithChart.ComponentDocumentWithChartPieExcel(components);
menuStrip = new MenuStrip();
аккаунтыToolStripMenuItem = new ToolStripMenuItem();
создатьToolStripMenuItem = new ToolStripMenuItem();
редактироватьToolStripMenuItem = new ToolStripMenuItem();
удалитьToolStripMenuItem = new ToolStripMenuItem();
отчётыToolStripMenuItem = new ToolStripMenuItem();
документСТекстомToolStripMenuItem = new ToolStripMenuItem();
документСТаблицейToolStripMenuItem = new ToolStripMenuItem();
документСДиаграммойToolStripMenuItem = new ToolStripMenuItem();
ролиToolStripMenuItem = new ToolStripMenuItem();
menuStrip.SuspendLayout();
SuspendLayout();
//
// controlDataTreeTable
//
this.controlDataTreeTable.Dock = System.Windows.Forms.DockStyle.Fill;
this.controlDataTreeTable.Location = new System.Drawing.Point(0, 28);
this.controlDataTreeTable.Name = "controlDataTreeTable";
this.controlDataTreeTable.Size = new System.Drawing.Size(800, 422);
this.controlDataTreeTable.TabIndex = 1;
//
// menuStrip
//
this.menuStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.аккаунтыToolStripMenuItem,
this.отчётыToolStripMenuItem,
this.ролиToolStripMenuItem});
this.menuStrip.Location = new System.Drawing.Point(0, 0);
this.menuStrip.Name = "menuStrip";
this.menuStrip.Size = new System.Drawing.Size(800, 28);
this.menuStrip.TabIndex = 0;
this.menuStrip.Text = "Контекстное меню";
//
// аккаунтыToolStripMenuItem
//
this.аккаунтыToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.создатьToolStripMenuItem,
this.редактироватьToolStripMenuItem,
this.удалитьToolStripMenuItem});
this.аккаунтыToolStripMenuItem.Name = "аккаунтыToolStripMenuItem";
this.аккаунтыToolStripMenuItem.Size = new System.Drawing.Size(88, 24);
this.аккаунтыToolStripMenuItem.Text = "Аккаунты";
//
// создатьToolStripMenuItem
//
this.создатьToolStripMenuItem.Name = "создатьToolStripMenuItem";
this.создатьToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.A)));
this.создатьToolStripMenuItem.Size = new System.Drawing.Size(246, 26);
this.создатьToolStripMenuItem.Text = "Создать";
this.создатьToolStripMenuItem.Click += new System.EventHandler(this.СоздатьToolStripMenuItem_Click);
//
// редактироватьToolStripMenuItem
//
this.редактироватьToolStripMenuItem.Name = "редактироватьToolStripMenuItem";
this.редактироватьToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.U)));
this.редактироватьToolStripMenuItem.Size = new System.Drawing.Size(246, 26);
this.редактироватьToolStripMenuItem.Text = "Редактировать";
this.редактироватьToolStripMenuItem.Click += new System.EventHandler(this.РедактироватьToolStripMenuItem_Click);
//
// удалитьToolStripMenuItem
//
this.удалитьToolStripMenuItem.Name = "удалитьToolStripMenuItem";
this.удалитьToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.D)));
this.удалитьToolStripMenuItem.Size = new System.Drawing.Size(246, 26);
this.удалитьToolStripMenuItem.Text = "Удалить";
this.удалитьToolStripMenuItem.Click += new System.EventHandler(this.УдалитьToolStripMenuItem_Click);
//
// отчётыToolStripMenuItem
//
this.отчётыToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.документСТекстомToolStripMenuItem,
this.документСТаблицейToolStripMenuItem,
this.документСДиаграммойToolStripMenuItem});
this.отчётыToolStripMenuItem.Name = "отчётыToolStripMenuItem";
this.отчётыToolStripMenuItem.Size = new System.Drawing.Size(73, 24);
this.отчётыToolStripMenuItem.Text = "Отчёты";
//
// документСТекстомToolStripMenuItem
//
this.документСТекстомToolStripMenuItem.Name = окументСТекстомToolStripMenuItem";
this.документСТекстомToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S)));
this.документСТекстомToolStripMenuItem.Size = new System.Drawing.Size(313, 26);
this.документСТекстомToolStripMenuItem.Text = "Документ с текстом";
this.документСТекстомToolStripMenuItem.Click += new System.EventHandler(this.ДокументСТекстомToolStripMenuItem_Click);
//
// документСТаблицейToolStripMenuItem
//
this.документСТаблицейToolStripMenuItem.Name = окументСТаблицейToolStripMenuItem";
this.документСТаблицейToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.T)));
this.документСТаблицейToolStripMenuItem.Size = new System.Drawing.Size(313, 26);
this.документСТаблицейToolStripMenuItem.Text = "Документ с таблицей";
this.документСТаблицейToolStripMenuItem.Click += new System.EventHandler(this.ДокументСТаблицейToolStripMenuItem_Click);
//
// документСДиаграммойToolStripMenuItem
//
this.документСДиаграммойToolStripMenuItem.Name = окументСДиаграммойToolStripMenuItem";
this.документСДиаграммойToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C)));
this.документСДиаграммойToolStripMenuItem.Size = new System.Drawing.Size(313, 26);
this.документСДиаграммойToolStripMenuItem.Text = "Документ с диаграммой";
this.документСДиаграммойToolStripMenuItem.Click += new System.EventHandler(this.ДокументСДиаграммойToolStripMenuItem_Click);
//
// ролиToolStripMenuItem
//
this.ролиToolStripMenuItem.Name = "ролиToolStripMenuItem";
this.ролиToolStripMenuItem.Size = new System.Drawing.Size(57, 24);
this.ролиToolStripMenuItem.Text = "Роли";
this.ролиToolStripMenuItem.Click += new System.EventHandler(this.РолиToolStripMenuItem_Click);
//
// FormMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.controlDataTreeTable);
this.Controls.Add(this.menuStrip);
this.MainMenuStrip = this.menuStrip;
this.Name = "FormMain";
this.Text = "Основная форма (аккаунты)";
this.Load += new System.EventHandler(this.FormMain_Load);
this.menuStrip.ResumeLayout(false);
this.menuStrip.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private ControlsLibraryNet60.Data.ControlDataTreeTable controlDataTreeTable;
private RodionovLibrary.NonVisualComponents.WordLongTextComponent wordLongTextComponent;
private ComponentsLibraryNet60.DocumentWithTable.ComponentDocumentWithTableMultiHeaderPdf componentDocumentWithTableMultiHeaderPdf;
private ComponentsLibraryNet60.DocumentWithChart.ComponentDocumentWithChartPieExcel componentDocumentWithChartPieExcel;
private MenuStrip menuStrip;
private ToolStripMenuItem аккаунтыToolStripMenuItem;
private ToolStripMenuItem создатьToolStripMenuItem;
private ToolStripMenuItem редактироватьToolStripMenuItem;
private ToolStripMenuItem удалитьToolStripMenuItem;
private ToolStripMenuItem отчётыToolStripMenuItem;
private ToolStripMenuItem документСТекстомToolStripMenuItem;
private ToolStripMenuItem документСТаблицейToolStripMenuItem;
private ToolStripMenuItem документСДиаграммойToolStripMenuItem;
private ToolStripMenuItem ролиToolStripMenuItem;
}
}

View File

@ -0,0 +1,217 @@
using ComponentsLibraryNet60.Models;
using ControlsLibraryNet60.Models;
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.ViewModels;
using RodionovLibrary.NonVisualComponents.HelperModels;
using System.Text;
namespace PortalAccountsView
{
public partial class FormMain : Form
{
private readonly IAccountLogic _logic;
public FormMain(IAccountLogic logic)
{
InitializeComponent();
_logic = logic;
var nodeNames = new Queue<string>();
nodeNames.Enqueue("RoleName");
nodeNames.Enqueue("OutputRating");
nodeNames.Enqueue("Id");
nodeNames.Enqueue("Login");
controlDataTreeTable.LoadConfig(new DataTreeNodeConfig { NodeNames = nodeNames });
}
private void ÐîëèToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormRoles));
if (service is FormRoles form)
{
form.ShowDialog();
}
}
private void FormMain_Load(object sender, EventArgs e)
{
LoadData();
}
private void LoadData()
{
controlDataTreeTable.Clear();
var accounts = _logic.ReadList(null);
if (accounts != null)
{
foreach (var account in accounts)
{
account.OutputRating = account.Rating?.ToString() ?? "Îòñóòñòâóåò";
}
controlDataTreeTable.AddTable(accounts);
}
}
private void ÑîçäàòüToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormAccount));
if (service is FormAccount form)
{
if (form.ShowDialog() == DialogResult.OK)
{
LoadData();
}
}
}
private void ÐåäàêòèðîâàòüToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormAccount));
if (service is FormAccount form)
{
var selected = controlDataTreeTable.GetSelectedObject<AccountViewModel>();
if (selected == null)
return;
form.Id = selected.Id;
if (form.ShowDialog() == DialogResult.OK)
{
LoadData();
}
}
}
private void ÓäàëèòüToolStripMenuItem_Click(object sender, EventArgs e)
{
var selected = controlDataTreeTable.GetSelectedObject<AccountViewModel>();
if (selected == null)
return;
if (MessageBox.Show("Óäàëèòü çàïèñü?", "", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
if (_logic.Delete(new AccountBindingModel { Id = selected.Id }))
{
LoadData();
}
}
}
private void ÄîêóìåíòÑÒåêñòîìToolStripMenuItem_Click(object sender, EventArgs e)
{
using var dialog = new SaveFileDialog
{
Filter = "docx|*.docx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
var accounts = _logic.ReadList(null) ?? throw new Exception("Íå óäàëîñü ïîëó÷èòü ñïèñîê àêêàóíòîâ");
List<string> paragraphs = new();
foreach (var account in accounts)
{
if (account.Rating == null)
{
paragraphs.Add($"{account.Login}: {(string.IsNullOrWhiteSpace(account.Warnings) ? "Ïðåäóïðåæäåíèÿ îòñóòñòâóþò" : account.Warnings)}");
}
}
wordLongTextComponent.CreateWordText(new WordLongTextInfo()
{
FileName = dialog.FileName,
Title = "Àêêàóíòû áåç ðåéòèíãà",
Paragraphs = paragraphs.ToArray()
});
MessageBox.Show("Ãîòîâî!");
}
catch (Exception ex)
{
MessageBox.Show("Ïðîèçîøëà îøèáêà: " + ex.Message, "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void ÄîêóìåíòÑÄèàãðàììîéToolStripMenuItem_Click(object sender, EventArgs e)
{
using var dialog = new SaveFileDialog
{
Filter = "Excel Files|*.xlsx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
var accounts = _logic.ReadList(null) ?? throw new Exception("Íå óäàëîñü ïîëó÷èòü ñïèñîê àêêàóíòîâ");
var roleMapping = new List<string>();
var data = new Dictionary<string, List<(int Date, double Value)>>
{
{
"Àêêàóíòû",
accounts
.Where(x => x.Rating != null)
.GroupBy(x => x.RoleName)
.Select((group, index) =>
{
roleMapping.Add($"{group.Key} - {index + 1}");
return (Date: index + 1, Value: (double)group.Count());
})
.ToList()
}
};
componentDocumentWithChartPieExcel.CreateDoc(new ComponentDocumentWithChartConfig
{
FilePath = dialog.FileName,
Header = $"Àêêàóíòû ñ ðåéòèíãîì ïî ðîëÿì ({string.Join(", ", roleMapping)})",
ChartTitle = "Êðóãîâàÿ äèàãðàììà",
LegendLocation = ComponentsLibraryNet60.Models.Location.Bottom,
Data = data
});
MessageBox.Show("Ãîòîâî!");
}
catch (Exception ex)
{
MessageBox.Show("Ïðîèçîøëà îøèáêà: " + ex.Message, "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void ÄîêóìåíòÑÒàáëèöåéToolStripMenuItem_Click(object sender, EventArgs e)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
using var dialog = new SaveFileDialog
{
Filter = "PDF Files|*.pdf"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
var accounts = _logic.ReadList(null) ?? throw new Exception("Íå óäàëîñü ïîëó÷èòü ñïèñîê àêêàóíòîâ");
foreach (var account in accounts)
{
account.OutputRating = account.Rating?.ToString() ?? "íåò";
}
componentDocumentWithTableMultiHeaderPdf.CreateDoc(new ComponentDocumentWithTableHeaderDataConfig<AccountViewModel>
{
FilePath = dialog.FileName,
Header = "Àêêàóíòû ïîðòàëà",
ColumnsRowsWidth = new List<(int, int)> { (10, 10), (10, 10), (10, 10), (10, 10)}, // øèðèíà ñòîëáöîâ è âûñîòà ñòðîê
Headers = new List<(int ColumnIndex, int RowIndex, string Header, string PropertyName)>
{
(0, 0, "Id", "Id"),
(1, 0, "Ëîãèí", "Login"),
(2, 0, "Ðîëü", "RoleName"),
(3, 0, "Ðåéòèíã", "OutputRating")
},
Data = accounts.OrderBy(x => x.Id).ToList()
});
MessageBox.Show("Ãîòîâî!");
}
catch (Exception ex)
{
MessageBox.Show("Ïðîèçîøëà îøèáêà: " + ex.Message, "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}

View File

@ -0,0 +1,132 @@
<?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="wordLongTextComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="componentDocumentWithTableMultiHeaderPdf.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>210, 17</value>
</metadata>
<metadata name="componentDocumentWithChartPieExcel.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>518, 17</value>
</metadata>
<metadata name="menuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>787, 17</value>
</metadata>
</root>

View File

@ -0,0 +1,87 @@
namespace PortalAccountsView
{
partial class FormRoles
{
/// <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()
{
dataGridView = new DataGridView();
NameCol = new DataGridViewTextBoxColumn();
Id = new DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
//
// dataGridView
//
dataGridView.BackgroundColor = SystemColors.ControlLightLight;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Columns.AddRange(new DataGridViewColumn[] { NameCol, Id });
dataGridView.Dock = DockStyle.Fill;
dataGridView.Location = new Point(0, 0);
dataGridView.Name = "dataGridView";
dataGridView.RowHeadersWidth = 51;
dataGridView.RowTemplate.Height = 29;
dataGridView.Size = new Size(800, 450);
dataGridView.TabIndex = 0;
dataGridView.CellValueChanged += DataGridView_CellValueChanged;
dataGridView.UserDeletingRow += DataGridView_UserDeletingRow;
dataGridView.KeyUp += DataGridView_KeyUp;
//
// NameCol
//
NameCol.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
NameCol.HeaderText = "Название";
NameCol.MinimumWidth = 6;
NameCol.Name = "NameCol";
//
// Id
//
Id.HeaderText = "Id";
Id.MinimumWidth = 6;
Id.Name = "Id";
Id.Visible = false;
Id.Width = 6;
//
// FormRoles
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(dataGridView);
Name = "FormRoles";
Text = "FormRoles";
Load += FormRoles_Load;
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
ResumeLayout(false);
}
#endregion
private DataGridView dataGridView;
private DataGridViewTextBoxColumn NameCol;
private DataGridViewTextBoxColumn Id;
}
}

View File

@ -0,0 +1,102 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
namespace PortalAccountsView
{
public partial class FormRoles : Form
{
private readonly IRoleLogic _logic;
private bool dataLoading = false;
public FormRoles(IRoleLogic logic)
{
InitializeComponent();
_logic = logic;
}
private void FormRoles_Load(object sender, EventArgs e)
{
LoadData();
}
private void LoadData()
{
dataLoading = true;
try
{
var list = _logic.ReadList(null);
if (list != null)
{
foreach (var role in list)
{
int rowIndex = dataGridView.Rows.Add();
dataGridView.Rows[rowIndex].Cells[0].Value = role.Name;
dataGridView.Rows[rowIndex].Cells[1].Value = role.Id;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
dataLoading = false;
}
}
private void DataGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (dataLoading || e.RowIndex < 0 || e.ColumnIndex != 0)
return;
if (dataGridView.Rows[e.RowIndex].Cells[1].Value != null) {
var name = dataGridView.Rows[e.RowIndex].Cells[0].Value?.ToString()
?? throw new Exception("Не заполнено название роли");
_logic.Update(new RoleBindingModel { Id = Convert.ToInt32(dataGridView.Rows[e.RowIndex].Cells[1].Value), Name = name });
}
else
{
var name = dataGridView.Rows[e.RowIndex].Cells[0].Value?.ToString()
?? throw new Exception("Не заполнено название роли");
_logic.Create(new RoleBindingModel { Id = 0, Name = name });
var list = _logic.ReadList(null) ?? throw new Exception("Не удалось получить список ролей");
int newRoleId = list.Last().Id;
dataGridView.Rows[e.RowIndex].Cells[1].Value = newRoleId;
}
}
private void DataGridView_KeyUp(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Insert:
dataGridView.Rows.Add();
break;
}
}
private void DeleteRows(DataGridViewSelectedRowCollection rows)
{
for (int i = 0; i < rows.Count; i++)
{
DataGridViewRow row = rows[i];
if (row.IsNewRow)
continue;
if (row.Cells[1].Value != null && !_logic.Delete(new RoleBindingModel { Id = Convert.ToInt32(row.Cells[1].Value) }))
throw new Exception($"Ошибка удаления строки: {row.Cells[0].Value}");
dataGridView.Rows.Remove(row);
}
}
private void DataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
e.Cancel = true;
if (dataGridView.SelectedRows == null)
return;
if (MessageBox.Show("Удалить записи?", "Подтвердите действие", MessageBoxButtons.YesNo) == DialogResult.No)
return;
DeleteRows(dataGridView.SelectedRows);
}
}
}

View File

@ -0,0 +1,123 @@
<?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="Id.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>

View File

@ -0,0 +1,30 @@
<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>
<PackageReference Include="ComponentsLibraryNet60" Version="1.0.0" />
<PackageReference Include="ControlsLibraryNet60" Version="1.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsBusinessLogic\PortalAccountsBusinessLogic.csproj" />
<ProjectReference Include="..\PortalAccountsContracts\PortalAccountsContracts.csproj" />
<ProjectReference Include="..\PortalAccountsDatabaseImplement\PortalAccountsDatabaseImplement.csproj" />
<ProjectReference Include="..\RodionovLibrary\RodionovLibrary.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,41 @@
using PortalAccountsBusinessLogic.BusinessLogics;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsDatabaseImplement.Implements;
using Microsoft.Extensions.DependencyInjection;
namespace PortalAccountsView
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
private static ServiceProvider? _serviceProvider;
public static ServiceProvider? ServiceProvider => _serviceProvider;
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
var services = new ServiceCollection();
ConfigureServices(services);
_serviceProvider = services.BuildServiceProvider();
Application.Run(_serviceProvider.GetRequiredService<FormMain>());
}
private static void ConfigureServices(ServiceCollection services)
{
services.AddTransient<IRoleStorage, RoleStorage>();
services.AddTransient<IAccountStorage, AccountStorage>();
services.AddTransient<IRoleLogic, RoleLogic>();
services.AddTransient<IAccountLogic, AccountLogic>();
services.AddTransient<FormMain>();
services.AddTransient<FormAccount>();
services.AddTransient<FormRoles>();
}
}
}

View File

@ -0,0 +1,16 @@
using System.Runtime.Serialization;
namespace RodionovLibrary.Exceptions
{
[Serializable]
public class NotMatchPatternException : ApplicationException
{
public NotMatchPatternException() : base() { }
public NotMatchPatternException(string message) : base(message) { }
public NotMatchPatternException(string message, Exception exception) : base(message, exception) { }
protected NotMatchPatternException(SerializationInfo info, StreamingContext contex) : base(info, contex) { }
}
}

View File

@ -0,0 +1,16 @@
using System.Runtime.Serialization;
namespace RodionovLibrary.Exceptions
{
[Serializable]
public class NullPatternException : ApplicationException
{
public NullPatternException() : base() { }
public NullPatternException(string message) : base(message) { }
public NullPatternException(string message, Exception exception) : base(message, exception) { }
protected NullPatternException(SerializationInfo info, StreamingContext contex) : base(info, contex) { }
}
}

View File

@ -0,0 +1,15 @@
namespace RodionovLibrary.NonVisualComponents.HelperEnums
{
public enum DiagramLegendLayout
{
None,
Left,
Top,
Right,
Bottom
}
}

View File

@ -0,0 +1,13 @@
namespace RodionovLibrary.NonVisualComponents.HelperModels
{
public class ColumnParameters
{
public string FirstRowHeader { get; set; } = string.Empty;
public string SecondRowHeader { get; set; } = string.Empty;
public string PropertyName { get; set; } = string.Empty;
public double Width { get; set; }
}
}

View File

@ -0,0 +1,11 @@
namespace RodionovLibrary.NonVisualComponents.HelperModels
{
public class SeriesParameters
{
public string SeriesName { get; set; } = string.Empty;
public List<double> ValuesY { get; set; } = new();
public Color Color { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using RodionovLibrary.NonVisualComponents.HelperEnums;
namespace RodionovLibrary.NonVisualComponents.HelperModels
{
public class WordDiagramInfo
{
public string FileName { get; set; } = string.Empty;
public string DocumentTitle { get; set; } = string.Empty;
public string DiagramTitle { get; set; } = string.Empty;
public DiagramLegendLayout LegendLayout { get; set; }
public List<string> CategoriesX { get; set; } = new();
public List<SeriesParameters> SeriesParameters { get; set; } = new();
}
}

View File

@ -0,0 +1,11 @@
namespace RodionovLibrary.NonVisualComponents.HelperModels
{
public class WordLongTextInfo
{
public string FileName { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string[] Paragraphs { get; set; } = Array.Empty<string>();
}
}

View File

@ -0,0 +1,15 @@
namespace RodionovLibrary.NonVisualComponents.HelperModels
{
public class WordTableInfo<T>
{
public string FileName { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public List<ColumnParameters> ColumnParameters { get; set; } = new();
public List<T> Items { get; set; } = new();
public List<(int, int)> MergedColumns { get; set; } = new();
}
}

View File

@ -0,0 +1,36 @@
namespace RodionovLibrary.NonVisualComponents
{
partial class WordDiagramComponent
{
/// <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,128 @@
using RodionovLibrary.NonVisualComponents.HelperEnums;
using RodionovLibrary.NonVisualComponents.HelperModels;
using Word = Microsoft.Office.Interop.Word;
using Excel = Microsoft.Office.Interop.Excel;
using System.ComponentModel;
namespace RodionovLibrary.NonVisualComponents
{
public partial class WordDiagramComponent : Component
{
public WordDiagramComponent()
{
InitializeComponent();
}
public WordDiagramComponent(IContainer container)
{
container.Add(this);
InitializeComponent();
}
public void CreateDiagramDocument(WordDiagramInfo diagramInfo)
{
ValidateDiagramInfo(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, WordDiagramInfo diagramInfo)
{
var paragraph = document.Paragraphs.Add();
var chartShape = document.InlineShapes.AddChart2(-1, (Microsoft.Office.Core.XlChartType)Excel.XlChartType.xlLine, 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.SeriesParameters.Count; i++)
{
var seriesInfo = diagramInfo.SeriesParameters[i];
var series = chartSeriesCollection.NewSeries();
series.Name = seriesInfo.SeriesName;
series.Values = seriesInfo.ValuesY.ToArray();
series.XValues = categoriesX;
SetSeriesColor(series, seriesInfo.Color);
series.MarkerStyle = Excel.XlMarkerStyle.xlMarkerStyleCircle;
series.MarkerSize = 5;
}
chart.HasLegend = true;
chart.Legend.Position = diagramInfo.LegendLayout switch
{
DiagramLegendLayout.Left => Word.XlLegendPosition.xlLegendPositionLeft,
DiagramLegendLayout.Top => Word.XlLegendPosition.xlLegendPositionTop,
DiagramLegendLayout.Right => Word.XlLegendPosition.xlLegendPositionRight,
DiagramLegendLayout.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);
}
private void ValidateDiagramInfo(WordDiagramInfo diagramInfo)
{
if (string.IsNullOrEmpty(diagramInfo.FileName) || string.IsNullOrEmpty(diagramInfo.DocumentTitle) ||
string.IsNullOrEmpty(diagramInfo.DiagramTitle) || diagramInfo.CategoriesX == null ||
diagramInfo.CategoriesX.Count == 0 || diagramInfo.SeriesParameters == null ||
diagramInfo.SeriesParameters.Count == 0)
{
throw new ArgumentException("Не все данные для диаграммы заполнены");
}
foreach (var series in diagramInfo.SeriesParameters)
{
if (string.IsNullOrEmpty(series.SeriesName))
{
throw new ArgumentException("Название серии не может быть пустым");
}
if (series.ValuesY == null || series.ValuesY.Count == 0)
{
throw new ArgumentException($"Список значений оси Y для серии '{series.SeriesName}' не заполнен");
}
if (diagramInfo.CategoriesX.Count != series.ValuesY.Count)
{
throw new ArgumentException($"Количество категорий оси X и значений оси Y для серии '{series.SeriesName}' не совпадает");
}
}
}
}
}

View File

@ -0,0 +1,36 @@
namespace RodionovLibrary.NonVisualComponents
{
partial class WordLongTextComponent
{
/// <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,86 @@
using Microsoft.Office.Interop.Word;
using RodionovLibrary.NonVisualComponents.HelperModels;
using System.ComponentModel;
using Application = Microsoft.Office.Interop.Word.Application;
namespace RodionovLibrary.NonVisualComponents
{
public partial class WordLongTextComponent : Component
{
private Application? _wordApp;
private Document? _document;
public WordLongTextComponent()
{
InitializeComponent();
}
public WordLongTextComponent(IContainer container)
{
container.Add(this);
InitializeComponent();
}
public void CreateWordText(WordLongTextInfo textInfo)
{
if (string.IsNullOrEmpty(textInfo.FileName) || string.IsNullOrEmpty(textInfo.Title) || !CheckData(textInfo.Paragraphs))
{
throw new ArgumentException("Не все данные заполнены");
}
_wordApp = new Application();
_document = _wordApp.Documents.Add();
try
{
AddText(textInfo);
_document.SaveAs2(textInfo.FileName);
}
finally
{
_document.Close();
_wordApp.Quit();
}
}
private void AddText(WordLongTextInfo textInfo)
{
if (_document == null)
{
return;
}
AddParagraph(textInfo.Title, fontSize: 22, isBold: true);
foreach (var paragraph in textInfo.Paragraphs)
{
AddParagraph(paragraph, fontSize: 14, isBold: false);
}
}
private void AddParagraph(string text, int fontSize, bool isBold)
{
if (_document == null)
{
return;
}
var paragraph = _document.Content.Paragraphs.Add();
var range = paragraph.Range;
range.Text = text;
range.Font.Size = fontSize;
range.Font.Name = "Times New Roman";
range.Font.Bold = isBold ? 1 : 0;
paragraph.Alignment = WdParagraphAlignment.wdAlignParagraphJustify;
range.InsertParagraphAfter();
}
private bool CheckData(string[] data)
{
return data != null && data.Any() && data.All(d => !string.IsNullOrEmpty(d));
}
}
}

View File

@ -0,0 +1,36 @@
namespace RodionovLibrary.NonVisualComponents
{
partial class WordTableComponent
{
/// <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,197 @@
using Word = Microsoft.Office.Interop.Word;
using System.ComponentModel;
using RodionovLibrary.NonVisualComponents.HelperModels;
namespace RodionovLibrary.NonVisualComponents
{
public partial class WordTableComponent : Component
{
public WordTableComponent()
{
InitializeComponent();
}
public WordTableComponent(IContainer container)
{
container.Add(this);
InitializeComponent();
}
public void CreateTable<T>(WordTableInfo<T> tableInfo)
{
ValidateInputData(tableInfo);
var wordApp = new Word.Application();
var document = wordApp.Documents.Add();
var range = document.Range();
var paragraph = range.Paragraphs.Add();
paragraph.Range.Text = tableInfo.Title;
paragraph.Range.Font.Name = "Times New Roman";
paragraph.Range.Font.Size = 18;
paragraph.Range.Font.Bold = 1;
paragraph.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Range.ParagraphFormat.SpaceAfter = 8;
paragraph.Range.InsertParagraphAfter();
var table = document.Tables.Add(paragraph.Range, tableInfo.Items.Count + 2, tableInfo.ColumnParameters.Count);
table.Borders.Enable = 1;
table.Range.Font.Name = "Times New Roman";
table.Range.Font.Size = 11;
for (int i = 0; i < tableInfo.ColumnParameters.Count; i++)
{
table.Columns[i + 1].Width = (float)(tableInfo.ColumnParameters[i].Width * 28.35);
}
AddTableHeaderRow(table, tableInfo.ColumnParameters, true);
AddTableHeaderRow(table, tableInfo.ColumnParameters, false);
MergeColumns(table, tableInfo.MergedColumns);
AddTableData(table, tableInfo.Items, tableInfo.ColumnParameters);
document.SaveAs2(tableInfo.FileName);
wordApp.Quit();
}
private void AddTableHeaderRow(Word.Table table, List<ColumnParameters> columnParameters, bool isFirstRow)
{
for (int i = 0; i < columnParameters.Count; i++)
{
var header = isFirstRow ? columnParameters[i].FirstRowHeader : columnParameters[i].SecondRowHeader;
if (!string.IsNullOrEmpty(header))
{
var cell = table.Cell(isFirstRow ? 1 : 2, i + 1);
cell.Range.Text = header;
cell.Range.Bold = 1;
cell.Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
cell.VerticalAlignment = Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter;
cell.Range.ParagraphFormat.SpaceBefore = 4;
cell.Range.ParagraphFormat.SpaceAfter = 4;
}
}
}
private void MergeColumns(Word.Table table, List<(int start, int end)> mergedColumns)
{
for (int i = 1; i <= table.Columns.Count; i++)
{
bool isMergedHorizontally = mergedColumns.Any(m => m.start <= i - 1 && m.end >= i - 1);
if (!isMergedHorizontally)
{
table.Cell(1, i).Merge(table.Cell(2, i));
}
}
int xOffset = 0;
foreach (var (start, end) in mergedColumns)
{
var cellStart = table.Cell(1, start + 1 - xOffset);
var cellEnd = table.Cell(1, end + 1 - xOffset);
string textToKeep = cellStart.Range.Text.TrimEnd('\r', '\a');
cellStart.Merge(cellEnd);
cellStart.Range.Text = textToKeep;
xOffset += end - start;
}
}
private void AddTableData<T>(Word.Table table, List<T> items, List<ColumnParameters> columnParameters)
{
for (int rowIndex = 0; rowIndex < items.Count; rowIndex++)
{
var item = items[rowIndex];
for (int colIndex = 0; colIndex < columnParameters.Count; colIndex++)
{
var property = typeof(T).GetProperty(columnParameters[colIndex].PropertyName);
var value = property?.GetValue(item)?.ToString() ?? string.Empty;
table.Cell(rowIndex + 3, colIndex + 1).Range.Text = value;
table.Cell(rowIndex + 3, colIndex + 1).Range.Bold = 0;
table.Cell(rowIndex + 3, colIndex + 1).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
table.Cell(rowIndex + 3, colIndex + 1).VerticalAlignment = Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter;
table.Cell(rowIndex + 3, colIndex + 1).Range.ParagraphFormat.SpaceBefore = 2;
table.Cell(rowIndex + 3, colIndex + 1).Range.ParagraphFormat.SpaceAfter = 2;
}
}
}
private void ValidateInputData<T>(WordTableInfo<T> tableInfo)
{
if (string.IsNullOrEmpty(tableInfo.FileName) || string.IsNullOrEmpty(tableInfo.Title))
{
throw new ArgumentException("Не все данные заполнены");
}
CheckColumnParameters(tableInfo.ColumnParameters);
if (tableInfo.Items == null || tableInfo.Items.Count == 0)
{
throw new ArgumentException("Данные для основной части таблицы не заданы");
}
foreach (var column in tableInfo.ColumnParameters)
{
if (typeof(T).GetProperty(column.PropertyName) == null)
{
throw new ArgumentException($"Свойство '{column.PropertyName}' не найдено в классе {typeof(T).Name}.");
}
}
ValidateMergedColumns(tableInfo.MergedColumns, tableInfo.ColumnParameters.Count);
}
private void CheckColumnParameters(List<ColumnParameters> columnParameters)
{
if (columnParameters == null || columnParameters.Count == 0)
{
throw new ArgumentException("Не заданы колонки для таблицы");
}
foreach (var column in columnParameters)
{
if (string.IsNullOrEmpty(column.FirstRowHeader) && string.IsNullOrEmpty(column.SecondRowHeader))
{
throw new ArgumentException("Заголовок не задан для одной из колонок в таблице");
}
if (column.Width <= 0)
{
throw new ArgumentException("Ширина колонки должна быть больше нуля.");
}
if (string.IsNullOrEmpty(column.PropertyName))
{
throw new ArgumentException("Свойство не задано для одной из колонок.");
}
}
}
private void ValidateMergedColumns(List<(int start, int end)> mergedColumns, int totalColumns)
{
if (mergedColumns == null || mergedColumns.Count == 0)
{
return;
}
foreach (var (start, end) in mergedColumns)
{
if (start < 0 || end >= totalColumns)
{
throw new ArgumentException("Индексы объединенных колонок выходят за пределы допустимых значений.");
}
var overlappingRanges = mergedColumns
.Where(m => m != (start, end))
.Any(m => m.start <= end && m.end >= start);
if (overlappingRanges)
{
throw new ArgumentException("Объединенные ячейки пересекаются.");
}
}
}
}
}

View File

@ -5,6 +5,37 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<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>
<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>
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,60 @@
namespace RodionovLibrary.VisualComponents
{
partial class ComboBoxControl
{
/// <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()
{
comboBox = new ComboBox();
SuspendLayout();
//
// comboBox
//
comboBox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
comboBox.FormattingEnabled = true;
comboBox.Location = new Point(1, 0);
comboBox.Margin = new Padding(3, 4, 3, 4);
comboBox.Name = "comboBox";
comboBox.Size = new Size(874, 28);
comboBox.TabIndex = 0;
comboBox.SelectedIndexChanged += ComboBox_SelectedIndexChanged;
//
// ComboBoxControl
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(comboBox);
Margin = new Padding(3, 4, 3, 4);
Name = "ComboBoxControl";
Size = new Size(875, 35);
ResumeLayout(false);
}
#endregion
private ComboBox comboBox;
}
}

View File

@ -0,0 +1,51 @@
namespace RodionovLibrary.VisualComponents
{
public partial class ComboBoxControl : UserControl
{
private event EventHandler? _valueChanged;
public event EventHandler ValueChanged
{
add { _valueChanged += value; }
remove { _valueChanged -= value; }
}
public string SelectedValue
{
get
{
return comboBox.SelectedItem?.ToString() ?? "";
}
set
{
if (comboBox.Items.Contains(value))
{
comboBox.SelectedItem = value;
}
}
}
public ComboBoxControl()
{
InitializeComponent();
}
public void AddItems(List<string> items)
{
foreach (string item in items)
{
comboBox.Items.Add(item);
}
}
public void Clear()
{
comboBox.Items.Clear();
}
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
_valueChanged?.Invoke(sender, 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,58 @@
namespace RodionovLibrary.VisualComponents
{
partial class ListBoxControl
{
/// <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()
{
listBox = new ListBox();
SuspendLayout();
//
// listBox
//
listBox.Dock = DockStyle.Fill;
listBox.FormattingEnabled = true;
listBox.ItemHeight = 15;
listBox.Location = new Point(0, 0);
listBox.Name = "listBox";
listBox.Size = new Size(567, 367);
listBox.TabIndex = 0;
//
// ListBoxControl
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(listBox);
Name = "ListBoxControl";
Size = new Size(567, 367);
ResumeLayout(false);
}
#endregion
private ListBox listBox;
}
}

View File

@ -0,0 +1,149 @@
using System.Reflection;
namespace RodionovLibrary.VisualComponents
{
public partial class ListBoxControl : UserControl
{
private string? _template;
private char? _fromChar;
private char? _toChar;
public int SelectedIndex
{
get
{
return listBox.SelectedIndex;
}
set
{
listBox.SelectedIndex = value;
}
}
public ListBoxControl()
{
InitializeComponent();
}
public void SetParams(string template, char fromChar, char toChar)
{
_template = template;
_fromChar = fromChar;
_toChar = toChar;
}
public T? GetObject<T>()
{
if (listBox.SelectedIndex == -1 || string.IsNullOrEmpty(_template) || !_fromChar.HasValue || !_toChar.HasValue)
throw new ArgumentException("Не хватает данных");
var type = typeof(T);
var fields = type.GetFields();
var properties = type.GetProperties();
var members = fields.Cast<MemberInfo>().Concat(properties.Cast<MemberInfo>()).ToArray();
var curObject = Activator.CreateInstance(type) ?? throw new Exception("Не получилось создать объект заданного типа");
string text = listBox.SelectedItem?.ToString() ?? "";
var fixedParts = System.Text.RegularExpressions.Regex.Split(_template, $@"\{_fromChar.Value}.*?\{_toChar.Value}");
int firstFixedStart = text.IndexOf(fixedParts[0], 0);
if (firstFixedStart == -1)
throw new Exception("Не найден элемент шаблона");
if (firstFixedStart != 0)
{
string beginning = text[..firstFixedStart];
FillMember(_template.Substring(1, firstFixedStart - 2), curObject, beginning, members);
}
int start = 0;
for (int i = 0; i < fixedParts.Length - 1; i++)
{
start = text.IndexOf(fixedParts[i], start);
if (start == -1)
throw new Exception("Не найден элемент шаблона");
start += fixedParts[i].Length;
int nextFixedIndex = text.IndexOf(fixedParts[i + 1], start);
if (nextFixedIndex == -1)
throw new Exception("Не найден следующий элемент шаблона");
string valueBetween = text[start..nextFixedIndex];
string templatePart = _template.Substring(_template.IndexOf(fixedParts[i]) + fixedParts[i].Length);
int startCharIndex = templatePart.IndexOf(_fromChar.Value);
int endCharIndex = templatePart.IndexOf(_toChar.Value);
string memberName = templatePart.Substring(startCharIndex + 1, endCharIndex - startCharIndex - 1);
FillMember(memberName, curObject, valueBetween, members);
start = nextFixedIndex;
}
return (T?)curObject;
}
public void AddItems<T>(List<T> items)
where T : class
{
if (string.IsNullOrEmpty(_template) || !_fromChar.HasValue || !_toChar.HasValue)
throw new ArgumentException("Не хватает данных");
listBox.Items.Clear();
var type = typeof(T);
var fields = type.GetFields();
var properties = type.GetProperties();
var members = fields.Cast<MemberInfo>().Concat(properties.Cast<MemberInfo>()).ToArray();
foreach (T item in items)
{
string result = _template;
foreach (var member in members)
{
string search = _fromChar.Value + member.Name + _toChar.Value;
object? value = null;
if (member is FieldInfo field)
{
value = field.GetValue(item);
}
if (member is PropertyInfo property)
{
if (property.CanRead)
{
value = property.GetValue(item);
}
}
result = result.Replace(search, value?.ToString() ?? "");
}
listBox.Items.Add(result);
}
}
private void FillMember(string memberName, object curObject, string value, MemberInfo[]? members)
{
var member = members?.FirstOrDefault(x => x.Name == memberName)
?? throw new Exception("Ошибка с поиском элемента");
object convertedValue = Convert.ChangeType(value, GetMemberType(member));
SetMemberValue(curObject, member, convertedValue);
}
private Type GetMemberType(MemberInfo member)
{
return member is PropertyInfo property ? property.PropertyType : ((FieldInfo)member).FieldType;
}
private void SetMemberValue(object obj, MemberInfo member, object value)
{
if (member is PropertyInfo property)
{
property.SetValue(obj, value);
}
else if (member is FieldInfo field)
{
field.SetValue(obj, value);
}
}
}
}

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,62 @@
namespace RodionovLibrary.VisualComponents
{
partial class TextBoxControl
{
/// <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();
textBox = new TextBox();
toolTip = new ToolTip(components);
SuspendLayout();
//
// textBox
//
textBox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
textBox.Location = new Point(0, 0);
textBox.Name = "textBox";
textBox.Size = new Size(213, 23);
textBox.TabIndex = 0;
textBox.TextChanged += TextBox_TextChanged;
textBox.MouseEnter += TextBox_MouseEnter;
//
// TextBoxControl
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(textBox);
Name = "TextBoxControl";
Size = new Size(216, 26);
ResumeLayout(false);
PerformLayout();
}
#endregion
private TextBox textBox;
private ToolTip toolTip;
}
}

View File

@ -0,0 +1,57 @@
using RodionovLibrary.Exceptions;
using System.Text.RegularExpressions;
namespace RodionovLibrary.VisualComponents
{
public partial class TextBoxControl : UserControl
{
private string? tooltipText;
private event EventHandler? _valueChanged;
public event EventHandler ValueChanged
{
add { _valueChanged += value; }
remove { _valueChanged -= value; }
}
public string? Pattern { get; set; }
public string Value {
get
{
if (string.IsNullOrEmpty(Pattern))
throw new NullPatternException("Не задан шаблон");
if (!new Regex(Pattern).IsMatch(textBox.Text))
throw new NotMatchPatternException("Введенное значение не соответствует шаблону");
return textBox.Text;
}
set
{
if (!string.IsNullOrEmpty(Pattern) && new Regex(Pattern).IsMatch(value))
textBox.Text = value;
}
}
public TextBoxControl()
{
InitializeComponent();
}
public void SetTooltipText(string text)
{
tooltipText = text;
}
private void TextBox_TextChanged(object sender, EventArgs e)
{
_valueChanged?.Invoke(sender, e);
}
private void TextBox_MouseEnter(object sender, EventArgs e)
{
toolTip.Show(tooltipText ?? "", textBox, 45, 20, 3000);
}
}
}

View File

@ -0,0 +1,123 @@
<?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="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

25
COP/WinForms/Employee.cs Normal file
View File

@ -0,0 +1,25 @@
namespace WinForms
{
public class Employee
{
public int Id { get; set; }
public string Status { get; set; } = string.Empty;
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public int Age { get; set; }
public string Children { get; set; } = string.Empty;
public string Car { get; set; } = string.Empty;
public string Department { get; set; } = string.Empty;
public string Position { get; set; } = string.Empty;
public double Bonus { get; set; }
}
}

View File

@ -1,39 +0,0 @@
namespace WinForms
{
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()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
}
#endregion
}
}

View File

@ -1,10 +0,0 @@
namespace WinForms
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}

277
COP/WinForms/FormTest.Designer.cs generated Normal file
View File

@ -0,0 +1,277 @@
namespace WinForms
{
partial class FormTest
{
/// <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();
comboBoxControl = new RodionovLibrary.VisualComponents.ComboBoxControl();
listBoxControl = new RodionovLibrary.VisualComponents.ListBoxControl();
textBoxControl = new RodionovLibrary.VisualComponents.TextBoxControl();
buttonClear = new Button();
buttonGetComboBox = new Button();
buttonSetComboBox = new Button();
buttonGetTextBox = new Button();
buttonSetTextBox = new Button();
buttonSetWrongTextBox = new Button();
buttonGetObject = new Button();
buttonGetIndex = new Button();
buttonSetIndex = new Button();
panel1 = new Panel();
buttonWordDiagram = new Button();
buttonWordTable = new Button();
buttonWordText = new Button();
wordLongTextComponent = new RodionovLibrary.NonVisualComponents.WordLongTextComponent(components);
wordTableComponent = new RodionovLibrary.NonVisualComponents.WordTableComponent(components);
wordDiagramComponent = new RodionovLibrary.NonVisualComponents.WordDiagramComponent(components);
panel1.SuspendLayout();
SuspendLayout();
//
// comboBoxControl
//
comboBoxControl.AutoSize = true;
comboBoxControl.AutoSizeMode = AutoSizeMode.GrowAndShrink;
comboBoxControl.Location = new Point(39, 125);
comboBoxControl.Name = "comboBoxControl";
comboBoxControl.SelectedValue = "";
comboBoxControl.Size = new Size(185, 26);
comboBoxControl.TabIndex = 0;
//
// listBoxControl
//
listBoxControl.AutoSize = true;
listBoxControl.AutoSizeMode = AutoSizeMode.GrowAndShrink;
listBoxControl.Location = new Point(39, 312);
listBoxControl.Name = "listBoxControl";
listBoxControl.SelectedIndex = -1;
listBoxControl.Size = new Size(567, 367);
listBoxControl.TabIndex = 1;
//
// textBoxControl
//
textBoxControl.AutoSize = true;
textBoxControl.AutoSizeMode = AutoSizeMode.GrowAndShrink;
textBoxControl.Location = new Point(390, 125);
textBoxControl.Name = "textBoxControl";
textBoxControl.Pattern = null;
textBoxControl.Size = new Size(216, 26);
textBoxControl.TabIndex = 2;
//
// buttonClear
//
buttonClear.Location = new Point(41, 155);
buttonClear.Margin = new Padding(3, 2, 3, 2);
buttonClear.Name = "buttonClear";
buttonClear.Size = new Size(82, 22);
buttonClear.TabIndex = 3;
buttonClear.Text = "Отчистка";
buttonClear.UseVisualStyleBackColor = true;
buttonClear.Click += ButtonClear_Click;
//
// buttonGetComboBox
//
buttonGetComboBox.Location = new Point(41, 191);
buttonGetComboBox.Margin = new Padding(3, 2, 3, 2);
buttonGetComboBox.Name = "buttonGetComboBox";
buttonGetComboBox.Size = new Size(144, 22);
buttonGetComboBox.TabIndex = 4;
buttonGetComboBox.Text = "Получение значения";
buttonGetComboBox.UseVisualStyleBackColor = true;
buttonGetComboBox.Click += ButtonGetComboBox_Click;
//
// buttonSetComboBox
//
buttonSetComboBox.Location = new Point(41, 229);
buttonSetComboBox.Margin = new Padding(3, 2, 3, 2);
buttonSetComboBox.Name = "buttonSetComboBox";
buttonSetComboBox.Size = new Size(144, 22);
buttonSetComboBox.TabIndex = 5;
buttonSetComboBox.Text = "Установка значения";
buttonSetComboBox.UseVisualStyleBackColor = true;
buttonSetComboBox.Click += ButtonSetComboBox_Click;
//
// buttonGetTextBox
//
buttonGetTextBox.Location = new Point(390, 155);
buttonGetTextBox.Margin = new Padding(3, 2, 3, 2);
buttonGetTextBox.Name = "buttonGetTextBox";
buttonGetTextBox.Size = new Size(144, 22);
buttonGetTextBox.TabIndex = 6;
buttonGetTextBox.Text = "Получение значения";
buttonGetTextBox.UseVisualStyleBackColor = true;
buttonGetTextBox.Click += ButtonGetTextBox_Click;
//
// buttonSetTextBox
//
buttonSetTextBox.Location = new Point(390, 191);
buttonSetTextBox.Margin = new Padding(3, 2, 3, 2);
buttonSetTextBox.Name = "buttonSetTextBox";
buttonSetTextBox.Size = new Size(144, 22);
buttonSetTextBox.TabIndex = 7;
buttonSetTextBox.Text = "Установка значения";
buttonSetTextBox.UseVisualStyleBackColor = true;
buttonSetTextBox.Click += ButtonSetTextBox_Click;
//
// buttonSetWrongTextBox
//
buttonSetWrongTextBox.Location = new Point(390, 229);
buttonSetWrongTextBox.Margin = new Padding(3, 2, 3, 2);
buttonSetWrongTextBox.Name = "buttonSetWrongTextBox";
buttonSetWrongTextBox.Size = new Size(215, 22);
buttonSetWrongTextBox.TabIndex = 8;
buttonSetWrongTextBox.Text = "Установка значения (неверное)";
buttonSetWrongTextBox.UseVisualStyleBackColor = true;
buttonSetWrongTextBox.Click += ButtonSetWrongTextBox_Click;
//
// buttonGetObject
//
buttonGetObject.Location = new Point(612, 452);
buttonGetObject.Margin = new Padding(3, 2, 3, 2);
buttonGetObject.Name = "buttonGetObject";
buttonGetObject.Size = new Size(144, 22);
buttonGetObject.TabIndex = 9;
buttonGetObject.Text = "Получение объекта";
buttonGetObject.UseVisualStyleBackColor = true;
buttonGetObject.Click += ButtonGetObject_Click;
//
// buttonGetIndex
//
buttonGetIndex.Location = new Point(612, 492);
buttonGetIndex.Margin = new Padding(3, 2, 3, 2);
buttonGetIndex.Name = "buttonGetIndex";
buttonGetIndex.Size = new Size(144, 22);
buttonGetIndex.TabIndex = 10;
buttonGetIndex.Text = "Получение индекса";
buttonGetIndex.UseVisualStyleBackColor = true;
buttonGetIndex.Click += ButtonGetIndex_Click;
//
// buttonSetIndex
//
buttonSetIndex.Location = new Point(612, 532);
buttonSetIndex.Margin = new Padding(3, 2, 3, 2);
buttonSetIndex.Name = "buttonSetIndex";
buttonSetIndex.Size = new Size(144, 22);
buttonSetIndex.TabIndex = 11;
buttonSetIndex.Text = "Установка индекса";
buttonSetIndex.UseVisualStyleBackColor = true;
buttonSetIndex.Click += ButtonSetIndex_Click;
//
// panel1
//
panel1.BackColor = Color.White;
panel1.BorderStyle = BorderStyle.FixedSingle;
panel1.Controls.Add(buttonWordDiagram);
panel1.Controls.Add(buttonWordTable);
panel1.Controls.Add(buttonWordText);
panel1.Location = new Point(41, 10);
panel1.Name = "panel1";
panel1.Size = new Size(715, 100);
panel1.TabIndex = 12;
//
// buttonWordDiagram
//
buttonWordDiagram.Location = new Point(528, 29);
buttonWordDiagram.Margin = new Padding(3, 2, 3, 2);
buttonWordDiagram.Name = "buttonWordDiagram";
buttonWordDiagram.Size = new Size(135, 34);
buttonWordDiagram.TabIndex = 15;
buttonWordDiagram.Text = "Word (диаграмма)";
buttonWordDiagram.UseVisualStyleBackColor = true;
buttonWordDiagram.Click += ButtonWordDiagram_Click;
//
// buttonWordTable
//
buttonWordTable.Location = new Point(288, 29);
buttonWordTable.Margin = new Padding(3, 2, 3, 2);
buttonWordTable.Name = "buttonWordTable";
buttonWordTable.Size = new Size(135, 34);
buttonWordTable.TabIndex = 14;
buttonWordTable.Text = "Word (таблица)";
buttonWordTable.UseVisualStyleBackColor = true;
buttonWordTable.Click += ButtonWordTable_Click;
//
// buttonWordText
//
buttonWordText.Location = new Point(47, 29);
buttonWordText.Margin = new Padding(3, 2, 3, 2);
buttonWordText.Name = "buttonWordText";
buttonWordText.Size = new Size(135, 34);
buttonWordText.TabIndex = 13;
buttonWordText.Text = "Word (текст)";
buttonWordText.UseVisualStyleBackColor = true;
buttonWordText.Click += ButtonWordText_Click;
//
// FormTest
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(779, 692);
Controls.Add(panel1);
Controls.Add(buttonSetIndex);
Controls.Add(buttonGetIndex);
Controls.Add(buttonGetObject);
Controls.Add(buttonSetWrongTextBox);
Controls.Add(buttonSetTextBox);
Controls.Add(buttonGetTextBox);
Controls.Add(buttonSetComboBox);
Controls.Add(buttonGetComboBox);
Controls.Add(buttonClear);
Controls.Add(textBoxControl);
Controls.Add(listBoxControl);
Controls.Add(comboBoxControl);
Margin = new Padding(3, 2, 3, 2);
Name = "FormTest";
StartPosition = FormStartPosition.CenterScreen;
Text = "FormTest";
panel1.ResumeLayout(false);
ResumeLayout(false);
PerformLayout();
}
#endregion
private RodionovLibrary.VisualComponents.ComboBoxControl comboBoxControl;
private RodionovLibrary.VisualComponents.ListBoxControl listBoxControl;
private RodionovLibrary.VisualComponents.TextBoxControl textBoxControl;
private Button buttonClear;
private Button buttonGetComboBox;
private Button buttonSetComboBox;
private Button buttonGetTextBox;
private Button buttonSetTextBox;
private Button buttonSetWrongTextBox;
private Button buttonGetObject;
private Button buttonGetIndex;
private Button buttonSetIndex;
private Panel panel1;
private Button buttonWordDiagram;
private Button buttonWordTable;
private Button buttonWordText;
private RodionovLibrary.NonVisualComponents.WordLongTextComponent wordLongTextComponent;
private RodionovLibrary.NonVisualComponents.WordTableComponent wordTableComponent;
private RodionovLibrary.NonVisualComponents.WordDiagramComponent wordDiagramComponent;
}
}

207
COP/WinForms/FormTest.cs Normal file
View File

@ -0,0 +1,207 @@
using RodionovLibrary.NonVisualComponents.HelperEnums;
using RodionovLibrary.NonVisualComponents.HelperModels;
namespace WinForms
{
public partial class FormTest : Form
{
public FormTest()
{
InitializeComponent();
comboBoxControl.AddItems(new List<string> { "Значение 1", "Значение 2", "Значение 3", "Значение 4", "Значение 5" });
textBoxControl.Pattern = @"^[a-z0-9._%+-]+\@([a-z0-9-]+\.)+[a-z]{2,4}$";
textBoxControl.SetTooltipText("example@gmail.com");
listBoxControl.SetParams("Имя: {FirstName}, фамилия: {LastName}. {Gender} ({Age}) лет.", '{', '}');
listBoxControl.AddItems(new List<Person> { new() { FirstName = "Кирилл", LastName = "Петров", Age = 23, Gender = "муж" },
new() { FirstName = "Мария", LastName = "Иванова", Age = 18, Gender = "жен" },
new() { FirstName = "Ева", LastName = "Панфилова", Age = 40, Gender = "жен" } });
}
private void ButtonClear_Click(object sender, EventArgs e)
{
comboBoxControl.Clear();
}
private void ButtonGetComboBox_Click(object sender, EventArgs e)
{
MessageBox.Show(comboBoxControl.SelectedValue, "Полученное значение");
}
private void ButtonSetComboBox_Click(object sender, EventArgs e)
{
comboBoxControl.SelectedValue = "Значение 3";
}
private void ButtonGetTextBox_Click(object sender, EventArgs e)
{
MessageBox.Show(textBoxControl.Value, "Полученное значение");
}
private void ButtonSetTextBox_Click(object sender, EventArgs e)
{
textBoxControl.Value = "forum98761@gmail.com";
}
private void ButtonSetWrongTextBox_Click(object sender, EventArgs e)
{
textBoxControl.Value = "smth";
}
private void ButtonGetObject_Click(object sender, EventArgs e)
{
Person? selectedPerson = listBoxControl.GetObject<Person>();
if (selectedPerson == null)
MessageBox.Show("Обьект пустой");
MessageBox.Show($"Имя: {selectedPerson?.FirstName}, Фамилия: {selectedPerson?.LastName}, " +
$"Возраст: {selectedPerson?.Age}, Пол: {selectedPerson?.Gender}");
}
private void ButtonGetIndex_Click(object sender, EventArgs e)
{
MessageBox.Show(listBoxControl.SelectedIndex.ToString(), "Полученное значение");
}
private void ButtonSetIndex_Click(object sender, EventArgs e)
{
listBoxControl.SelectedIndex = 0;
}
private void ButtonWordText_Click(object sender, EventArgs e)
{
using var dialog = new SaveFileDialog
{
Filter = "docx|*.docx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
wordLongTextComponent.CreateWordText(new WordLongTextInfo()
{
FileName = dialog.FileName,
Title = "ГЛАВА 1. Нежданные гости",
Paragraphs = new string[] { "Жил-был в норе под землей хоббит. Не в какой-то там мерзкой грязной сырой норе, где со всех сторон торчат хвосты червей и противно пахнет плесенью, но и не в сухой песчаной голой норе, где не на что сесть и нечего съесть. Нет, нора была хоббичья, а значит — благоустроенная.",
"Она начиналась идеально круглой, как иллюминатор, дверью, выкрашенной зеленой краской, с сияющей медной ручкой точно посередине. Дверь отворялась внутрь, в длинный коридор, похожий на железнодорожный туннель, но туннель без гари и без дыма и тоже очень благоустроенный: стены там были обшиты панелями, пол выложен плитками и устлан ковром, вдоль стен стояли полированные стулья, и всюду были прибиты крючочки для шляп и пальто, так как хоббит любил гостей.",
"Туннель вился все дальше и дальше и заходил довольно глубоко, но не в самую глубину Холма, как его именовали жители на много миль в окружности. По обеим сторонам туннеля шли двери — много-много круглых дверей. Хоббит не признавал восхождений по лестницам: спальни, ванные, погреба, кладовые (целая куча кладовых), гардеробные (хоббит отвел несколько комнат под хранение одежды), кухни, столовые располагались в одном этаже и, более того, в одном и том же коридоре.",
"Лучшие комнаты находились по левую руку, и только в них имелись окна — глубоко сидящие круглые окошечки с видом на сад и на дальние луга, спускавшиеся к реке."}
});
MessageBox.Show("Готово!");
}
catch (Exception ex)
{
MessageBox.Show("Произошла ошибка: " + ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void ButtonWordTable_Click(object sender, EventArgs e)
{
using var dialog = new SaveFileDialog
{
Filter = "docx|*.docx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
var columns = new List<ColumnParameters>
{
new() { FirstRowHeader = "Идент", PropertyName = "Id", Width = 1.3 },
new() { FirstRowHeader = "Статус", PropertyName = "Status", Width = 1.3 },
new() { FirstRowHeader = "Личные данные", SecondRowHeader = "Имя", PropertyName = "FirstName", Width = 1.7 },
new() { FirstRowHeader = "Личные данные", SecondRowHeader = "Фамилия", PropertyName = "LastName", Width = 1.7 },
new() { FirstRowHeader = "Личные данные", SecondRowHeader = "Возраст", PropertyName = "Age", Width = 1.7 },
new() { FirstRowHeader = "Дети", PropertyName = "Children", Width = 1.3 },
new() { FirstRowHeader = "Машина", PropertyName = "Car", Width = 1.7 },
new() { FirstRowHeader = "Работа", SecondRowHeader = "Подразделение", PropertyName = "Department", Width = 2.4 },
new() { FirstRowHeader = "Работа", SecondRowHeader = "Должность", PropertyName = "Position", Width = 2.4 },
new() { FirstRowHeader = "Премия", PropertyName = "Bonus", Width = 2 }
};
var employees = new List<Employee>
{
new() { Id = 1, Status = "нет", FirstName = "Иван", LastName = "Иванов", Age = 34, Children = "нет", Car = "есть", Department = "Департамент 1", Position = "Инженер", Bonus = 2000.1 },
new() { Id = 2, Status = "нет", FirstName = "Петр", LastName = "Петров", Age = 44, Children = "есть", Car = "есть", Department = "Департамент 1", Position = "Инженер", Bonus = 2000.1 },
new() { Id = 3, Status = "да", FirstName = "Сергей", LastName = "Сергеев", Age = 55, Children = "нет", Car = "нет", Department = "Департамент 1", Position = "Руководитель", Bonus = 5000.5 },
new() { Id = 4, Status = "нет", FirstName = "Ольга", LastName = "Иванова", Age = 34, Children = "есть", Car = "нет", Department = "Бухгалтерия", Position = "Бухгалтер", Bonus = 2000.1 },
new() { Id = 5, Status = "да", FirstName = "Татьяна", LastName = "Петрова", Age = 44, Children = "нет", Car = "нет", Department = "Бухгалтерия", Position = "Старший бухгалтер", Bonus = 7000.6 }
};
var mergedColumns = new List<(int, int)>
{
(2, 4),
(7, 8)
};
var tableInfo = new WordTableInfo<Employee>
{
FileName = dialog.FileName,
Title = "Заголовок",
ColumnParameters = columns,
Items = employees,
MergedColumns = mergedColumns
};
wordTableComponent.CreateTable(tableInfo);
MessageBox.Show("Готово!");
}
catch (Exception ex)
{
MessageBox.Show("Произошла ошибка: " + ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void ButtonWordDiagram_Click(object sender, EventArgs e)
{
using var dialog = new SaveFileDialog
{
Filter = "docx|*.docx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
var series = new List<SeriesParameters>
{
new() {
SeriesName = "Серия 1",
ValuesY = new List<double> { 10, 15, 20 },
Color = Color.FromArgb(255, 165, 0)
},
new() {
SeriesName = "Серия 2",
ValuesY = new List<double> { 45, 34, 18 },
Color = Color.FromArgb(105, 105, 105)
},
new() {
SeriesName = "Серия 3",
ValuesY = new List<double> { 25, 2, 7 },
Color = Color.FromArgb(255, 255, 0)
}
};
wordDiagramComponent.CreateDiagramDocument(new WordDiagramInfo()
{
FileName = dialog.FileName,
DocumentTitle = "Заголовок",
DiagramTitle = "Тестовая диаграмма",
LegendLayout = DiagramLegendLayout.Bottom,
CategoriesX = new List<string> { "Январь", "Февраль", "Март" },
SeriesParameters = series
});
MessageBox.Show("Готово!");
}
catch (Exception ex)
{
MessageBox.Show("Произошла ошибка: " + ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}

129
COP/WinForms/FormTest.resx Normal file
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="wordLongTextComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="wordTableComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>210, 17</value>
</metadata>
<metadata name="wordDiagramComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>382, 17</value>
</metadata>
</root>

13
COP/WinForms/Person.cs Normal file
View File

@ -0,0 +1,13 @@
namespace WinForms
{
public class Person
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public int Age { get; set; }
public string Gender { get; set; } = string.Empty;
}
}

View File

@ -11,7 +11,7 @@ namespace WinForms
// To customize application configuration such as set high DPI settings or default font, // To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration. // see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize(); ApplicationConfiguration.Initialize();
Application.Run(new Form1()); Application.Run(new FormTest());
} }
} }
} }

View File

@ -8,4 +8,8 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\RodionovLibrary\RodionovLibrary.csproj" />
</ItemGroup>
</Project> </Project>