Лабораторная 3

This commit is contained in:
Даниил Путинцев 2024-11-19 23:18:49 +04:00
parent fd98232cda
commit 48ae5ef9ad
40 changed files with 2357 additions and 2 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.10.35004.147 VisualStudioVersion = 17.10.35004.147
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PutincevLibrary", "PutincevLibrary\PutincevLibrary.csproj", "{BF0238D4-F38A-4670-8479-E8F6FE980F15}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PutincevLibrary", "PutincevLibrary\PutincevLibrary.csproj", "{BF0238D4-F38A-4670-8479-E8F6FE980F15}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinForms", "WinForms\WinForms.csproj", "{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinForms", "WinForms\WinForms.csproj", "{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsBusinessLogic", "PortalAccountsBusinessLogic\PortalAccountsBusinessLogic.csproj", "{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsContracts", "PortalAccountsContracts\PortalAccountsContracts.csproj", "{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsDatabaseImplement", "PortalAccountsDatabaseImplement\PortalAccountsDatabaseImplement.csproj", "{F39F4D94-6F88-472C-958A-41F523E5C458}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsDataModels", "PortalAccountsDataModels\PortalAccountsDataModels.csproj", "{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PortalAccountsView", "PortalAccountsView\PortalAccountsView.csproj", "{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -21,6 +31,26 @@ Global
{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Debug|Any CPU.Build.0 = Debug|Any CPU {2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Release|Any CPU.ActiveCfg = Release|Any CPU {2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Release|Any CPU.Build.0 = Release|Any CPU {2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Release|Any CPU.Build.0 = Release|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Release|Any CPU.Build.0 = Release|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Release|Any CPU.Build.0 = Release|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Release|Any CPU.Build.0 = Release|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Release|Any CPU.Build.0 = Release|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.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.InterestId <= 0)
{
throw new ArgumentNullException("Некорректный идентификатор интерес", nameof(model.InterestId));
}
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 InterestLogic : IInterestLogic
{
private readonly IInterestStorage _interestStorage;
public InterestLogic(IInterestStorage InterestStorage)
{
_interestStorage = InterestStorage;
}
public List<InterestViewModel>? ReadList(InterestSearchModel? model)
{
return model == null ? _interestStorage.GetFullList() : _interestStorage.GetFilteredList(model);
}
public InterestViewModel? ReadElement(InterestSearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
return _interestStorage.GetElement(model);
}
public bool Create(InterestBindingModel model)
{
CheckModel(model);
return _interestStorage.Insert(model) != null;
}
public bool Update(InterestBindingModel model)
{
CheckModel(model);
return _interestStorage.Update(model) != null;
}
public bool Delete(InterestBindingModel model)
{
CheckModel(model, false);
return _interestStorage.Delete(model) != null;
}
private void CheckModel(InterestBindingModel 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 = _interestStorage.GetElement(new InterestSearchModel
{
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? AvatarPath { get; set; }
public int InterestId { get; set; }
public string? Email { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using PortalAccountsDataModels.Models;
namespace PortalAccountsContracts.BindingModels
{
public class InterestBindingModel : IInterestModel
{
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 IInterestLogic
{
List<InterestViewModel>? ReadList(InterestSearchModel? model);
InterestViewModel? ReadElement(InterestSearchModel model);
bool Create(InterestBindingModel model);
bool Update(InterestBindingModel model);
bool Delete(InterestBindingModel 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? InterestId { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace PortalAccountsContracts.SearchModels
{
public class InterestSearchModel
{
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 IInterestStorage
{
List<InterestViewModel> GetFullList();
List<InterestViewModel> GetFilteredList(InterestSearchModel model);
InterestViewModel? GetElement(InterestSearchModel model);
InterestViewModel? Insert(InterestBindingModel model);
InterestViewModel? Update(InterestBindingModel model);
InterestViewModel? Delete(InterestBindingModel model);
}
}

View File

@ -0,0 +1,24 @@
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;
public string? AvatarPath { get; set; }
public int InterestId { get; set; }
[DisplayName("Интерес")]
public string InterestName { get; set; } = string.Empty;
[DisplayName("Почта")]
public string? Email { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using PortalAccountsDataModels.Models;
using System.ComponentModel;
namespace PortalAccountsContracts.ViewModels
{
public class InterestViewModel : IInterestModel
{
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? AvatarPath { get; }
int InterestId { get; }
string? Email { get; }
}
}

View File

@ -0,0 +1,7 @@
namespace PortalAccountsDataModels.Models
{
public interface IInterestModel : 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.Interest)
.Select(x => x.GetViewModel)
.ToList();
}
public List<AccountViewModel> GetFilteredList(AccountSearchModel model)
{
using var context = new PortalAccountsDatabase();
if (model.InterestId.HasValue)
{
return context.Accounts
.Include(x => x.Interest)
.Where(x => x.InterestId == model.InterestId)
.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.Interest)
.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.Interest)
.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.Interest)
.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.Interest)
.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 InterestStorage : IInterestStorage
{
public List<InterestViewModel> GetFullList()
{
using var context = new PortalAccountsDatabase();
return context.Interests
.Select(x => x.GetViewModel)
.ToList();
}
public List<InterestViewModel> GetFilteredList(InterestSearchModel model)
{
if (string.IsNullOrEmpty(model.Name))
{
return new();
}
using var context = new PortalAccountsDatabase();
return context.Interests
.Where(x => x.Name.Contains(model.Name))
.Select(x => x.GetViewModel)
.ToList();
}
public InterestViewModel? GetElement(InterestSearchModel model)
{
if (string.IsNullOrEmpty(model.Name) && !model.Id.HasValue)
{
return null;
}
using var context = new PortalAccountsDatabase();
return context.Interests
.FirstOrDefault(x => !string.IsNullOrEmpty(model.Name) && x.Name == model.Name ||
model.Id.HasValue && x.Id == model.Id)
?.GetViewModel;
}
public InterestViewModel? Insert(InterestBindingModel model)
{
var newInterest = Interest.Create(model);
if (newInterest == null)
{
return null;
}
using var context = new PortalAccountsDatabase();
context.Interests.Add(newInterest);
context.SaveChanges();
return newInterest.GetViewModel;
}
public InterestViewModel? Update(InterestBindingModel model)
{
using var context = new PortalAccountsDatabase();
var interest = context.Interests.FirstOrDefault(x => x.Id == model.Id);
if (interest == null)
{
return null;
}
interest.Update(model);
context.SaveChanges();
return interest.GetViewModel;
}
public InterestViewModel? Delete(InterestBindingModel model)
{
using var context = new PortalAccountsDatabase();
var element = context.Interests.FirstOrDefault(rec => rec.Id == model.Id);
if (element != null)
{
context.Interests.Remove(element);
context.SaveChanges();
return element.GetViewModel;
}
return null;
}
}
}

View File

@ -0,0 +1,90 @@
// <auto-generated />
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("20241106113420_migr")]
partial class migr
{
/// <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>("AvatarPath")
.HasColumnType("text");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("InterestId")
.HasColumnType("integer");
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("InterestId");
b.ToTable("Accounts");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", 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("Interests");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.HasOne("PortalAccountsDatabaseImplement.Models.Interest", "Interest")
.WithMany("Accounts")
.HasForeignKey("InterestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Interest");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", 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 migr : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Interests",
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_Interests", 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),
AvatarPath = table.Column<string>(type: "text", nullable: true),
InterestId = table.Column<int>(type: "integer", nullable: false),
Email = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Accounts", x => x.Id);
table.ForeignKey(
name: "FK_Accounts_Interests_InterestId",
column: x => x.InterestId,
principalTable: "Interests",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Accounts_InterestId",
table: "Accounts",
column: "InterestId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Accounts");
migrationBuilder.DropTable(
name: "Interests");
}
}
}

View File

@ -0,0 +1,87 @@
// <auto-generated />
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>("AvatarPath")
.HasColumnType("text");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("InterestId")
.HasColumnType("integer");
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("InterestId");
b.ToTable("Accounts");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", 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("Interests");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.HasOne("PortalAccountsDatabaseImplement.Models.Interest", "Interest")
.WithMany("Accounts")
.HasForeignKey("InterestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Interest");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", 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? AvatarPath { get; set; }
[Required]
public int InterestId { get; set; }
public string? Email { get; set; }
public virtual Interest Interest { get; set; }
public static Account? Create(AccountBindingModel? model)
{
if (model == null)
{
return null;
}
return new Account()
{
Id = model.Id,
Login = model.Login,
AvatarPath = model.AvatarPath,
InterestId = model.InterestId,
Email = model.Email
};
}
public void Update(AccountBindingModel? model)
{
if (model == null)
{
return;
}
Login = model.Login;
AvatarPath = model.AvatarPath;
InterestId = model.InterestId;
Email = model.Email;
}
public AccountViewModel GetViewModel => new()
{
Id = Id,
Login = Login,
AvatarPath = AvatarPath,
InterestId = InterestId,
InterestName = Interest.Name ?? string.Empty,
Email = Email
};
}
}

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 Interest : IInterestModel
{
public int Id { get; private set; }
[Required]
public string Name { get; private set; } = string.Empty;
[ForeignKey("InterestId")]
public virtual List<Account> Accounts { get; set; } = new();
public static Interest? Create(InterestBindingModel model)
{
if (model == null)
{
return null;
}
return new Interest()
{
Id = model.Id,
Name = model.Name
};
}
public void Update(InterestBindingModel model)
{
if (model == null)
{
return;
}
Name = model.Name;
}
public InterestViewModel 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;Port=6456;Database=put_portal_accounts_database;Username=postgres;Password=dan");
}
base.OnConfiguring(optionsBuilder);
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
public virtual DbSet<Account> Accounts { set; get; }
public virtual DbSet<Interest> Interests { 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,169 @@
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()
{
labelLogin = new Label();
labelInterest = new Label();
labelAvatar = new Label();
labelEmail = new Label();
buttonSave = new Button();
buttonCancel = new Button();
textBoxLogin = new TextBox();
customListBoxInterest = new Components.CustomListBox();
textBoxControlEmail = new RodionovLibrary.VisualComponents.TextBoxControl();
textBoxAvatar = new TextBox();
SuspendLayout();
//
// labelLogin
//
labelLogin.AutoSize = true;
labelLogin.Location = new Point(39, 17);
labelLogin.Name = "labelLogin";
labelLogin.Size = new Size(52, 20);
labelLogin.TabIndex = 0;
labelLogin.Text = "Логин";
//
// labelInterest
//
labelInterest.AutoSize = true;
labelInterest.Location = new Point(39, 99);
labelInterest.Name = "labelInterest";
labelInterest.Size = new Size(67, 20);
labelInterest.TabIndex = 1;
labelInterest.Text = "Интерес";
//
// labelAvatar
//
labelAvatar.AutoSize = true;
labelAvatar.Location = new Point(570, 17);
labelAvatar.Name = "labelAvatar";
labelAvatar.Size = new Size(58, 20);
labelAvatar.TabIndex = 2;
labelAvatar.Text = "Аватар";
//
// labelEmail
//
labelEmail.AutoSize = true;
labelEmail.Location = new Point(570, 138);
labelEmail.Name = "labelEmail";
labelEmail.Size = new Size(51, 20);
labelEmail.TabIndex = 3;
labelEmail.Text = "Почта";
//
// buttonSave
//
buttonSave.Location = new Point(277, 352);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(105, 36);
buttonSave.TabIndex = 9;
buttonSave.Text = "Сохранить";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += buttonSave_Click;
//
// buttonCancel
//
buttonCancel.Location = new Point(470, 352);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(105, 36);
buttonCancel.TabIndex = 10;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// textBoxLogin
//
textBoxLogin.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
textBoxLogin.Location = new Point(39, 56);
textBoxLogin.Name = "textBoxLogin";
textBoxLogin.Size = new Size(226, 27);
textBoxLogin.TabIndex = 11;
textBoxLogin.TextChanged += TextBoxLogin_TextChanged;
//
// customListBoxInterest
//
customListBoxInterest.Location = new Point(39, 123);
customListBoxInterest.Margin = new Padding(3, 4, 3, 4);
customListBoxInterest.Name = "customListBoxInterest";
customListBoxInterest.SelectedItem = "";
customListBoxInterest.Size = new Size(226, 157);
customListBoxInterest.TabIndex = 12;
//
// textBoxControlEmail
//
textBoxControlEmail.Location = new Point(451, 174);
textBoxControlEmail.Margin = new Padding(3, 4, 3, 4);
textBoxControlEmail.Name = "textBoxControlEmail";
textBoxControlEmail.Pattern = null;
textBoxControlEmail.Size = new Size(309, 44);
textBoxControlEmail.TabIndex = 13;
//
// textBoxAvatar
//
textBoxAvatar.Location = new Point(541, 58);
textBoxAvatar.Name = "textBoxAvatar";
textBoxAvatar.Size = new Size(125, 27);
textBoxAvatar.TabIndex = 14;
textBoxAvatar.Click += textBoxAvatar_Click;
//
// FormAccount
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(textBoxAvatar);
Controls.Add(textBoxControlEmail);
Controls.Add(customListBoxInterest);
Controls.Add(textBoxLogin);
Controls.Add(buttonCancel);
Controls.Add(buttonSave);
Controls.Add(labelEmail);
Controls.Add(labelAvatar);
Controls.Add(labelInterest);
Controls.Add(labelLogin);
Name = "FormAccount";
Text = "FormAccount";
Load += FormAccount_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label labelLogin;
private Label labelInterest;
private Label labelAvatar;
private Label labelEmail;
private Button buttonSave;
private Button buttonCancel;
private TextBox textBoxLogin;
private Components.CustomListBox customListBoxInterest;
private RodionovLibrary.VisualComponents.TextBoxControl textBoxControlEmail;
private TextBox textBoxAvatar;
}
}

View File

@ -0,0 +1,141 @@
using DocumentFormat.OpenXml.Vml.Office;
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
using RodionovLibrary.VisualComponents;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PortalAccountsView
{
public partial class FormAccount : Form
{
private int? _id;
private bool _isModified = false;
private readonly IAccountLogic _logic;
private readonly IInterestLogic _interestLogic;
private List<InterestViewModel> _interests;
public int Id { set { _id = value; } }
public FormAccount(IAccountLogic logic, IInterestLogic interestLogic)
{
InitializeComponent();
_logic = logic;
_interestLogic = interestLogic;
_interests = new List<InterestViewModel>();
customListBoxInterest.TextChanged += (_, _) => _isModified = true;
textBoxControlEmail.TextChanged += (_, _) => _isModified = true;
textBoxControlEmail.Pattern = @"^[a-z0-9._%+-]+\@([a-z0-9-]+\.)+[a-z]{2,4}$";
textBoxControlEmail.SetTooltipText("example@gmail.com");
}
private void FormAccount_Load(object sender, EventArgs e)
{
_interests = _interestLogic.ReadList(null) ?? throw new Exception("Не удалось получить список ролей");
customListBoxInterest.SetItems(_interests.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;
textBoxAvatar.Text = account.AvatarPath;
textBoxControlEmail.Text = account.Email;
customListBoxInterest.SelectedItem = account.InterestName;
_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(customListBoxInterest.SelectedItem))
{
MessageBox.Show("Выберите интерес", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
try
{
var model = new AccountBindingModel
{
Id = _id ?? 0,
Login = textBoxLogin.Text,
Email = textBoxControlEmail.Value,
AvatarPath = textBoxAvatar.Text,
InterestId = _interests.First(x => x.Name == customListBoxInterest.SelectedItem).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 textBoxAvatar_Click(object sender, EventArgs e)
{
using (var dialog = new OpenFileDialog { Filter = "jpg|*.jpg" })
{
if (dialog.ShowDialog() == DialogResult.OK)
{
textBoxAvatar.Text = dialog.FileName.ToString();
}
}
}
}
}

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,87 @@
namespace PortalAccountsView
{
partial class FormInterests
{
/// <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;
//
// FormInterestss
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(dataGridView);
Name = "FormInterestss";
Text = "FormInterestss";
Load += FormInterestss_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 FormInterests : Form
{
private readonly IInterestLogic _logic;
private bool dataLoading = false;
public FormInterests(IInterestLogic logic)
{
InitializeComponent();
_logic = logic;
}
private void FormInterestss_Load(object sender, EventArgs e)
{
LoadData();
}
private void LoadData()
{
dataLoading = true;
try
{
var list = _logic.ReadList(null);
if (list != null)
{
foreach (var interest in list)
{
int rowIndex = dataGridView.Rows.Add();
dataGridView.Rows[rowIndex].Cells[0].Value = interest.Name;
dataGridView.Rows[rowIndex].Cells[1].Value = interest.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 InterestBindingModel { 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 InterestBindingModel { Id = 0, Name = name });
var list = _logic.ReadList(null) ?? throw new Exception("Не удалось получить список интересов");
int newInterestsId = list.Last().Id;
dataGridView.Rows[e.RowIndex].Cells[1].Value = newInterestsId;
}
}
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 InterestBindingModel { 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,171 @@
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();
menuStrip1 = 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();
customDataGridViewTable = new Components.CustomDataGridView();
componentExcelWithImage = new PutincevLibrary.ComponentExcelWithImage(components);
wordTableComponent = new RodionovLibrary.NonVisualComponents.WordTableComponent(components);
histogrampdf = new Components.NonVisual.HistogramPDF(components);
menuStrip1.SuspendLayout();
SuspendLayout();
//
// menuStrip1
//
menuStrip1.ImageScalingSize = new Size(20, 20);
menuStrip1.Items.AddRange(new ToolStripItem[] { аккаунтыToolStripMenuItem, отчетыToolStripMenuItem, интересыToolStripMenuItem });
menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1";
menuStrip1.Size = new Size(800, 28);
menuStrip1.TabIndex = 0;
menuStrip1.Text = "menuStrip1";
//
// аккаунтыToolStripMenuItem
//
аккаунтыToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { создатьToolStripMenuItem, редактироватьToolStripMenuItem, удалитьToolStripMenuItem });
аккаунтыToolStripMenuItem.Name = "аккаунтыToolStripMenuItem";
аккаунтыToolStripMenuItem.Size = new Size(88, 24);
аккаунтыToolStripMenuItem.Text = "Аккаунты";
//
// создатьToolStripMenuItem
//
создатьToolStripMenuItem.Name = "создатьToolStripMenuItem";
создатьToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.A;
создатьToolStripMenuItem.Size = new Size(246, 26);
создатьToolStripMenuItem.Text = "Создать";
создатьToolStripMenuItem.Click += создатьToolStripMenuItem_Click;
//
// редактироватьToolStripMenuItem
//
редактироватьToolStripMenuItem.Name = "редактироватьToolStripMenuItem";
редактироватьToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.U;
редактироватьToolStripMenuItem.Size = new Size(246, 26);
редактироватьToolStripMenuItem.Text = "Редактировать";
редактироватьToolStripMenuItem.Click += редактироватьToolStripMenuItem_Click;
//
// удалитьToolStripMenuItem
//
удалитьToolStripMenuItem.Name = "удалитьToolStripMenuItem";
удалитьToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.D;
удалитьToolStripMenuItem.Size = new Size(246, 26);
удалитьToolStripMenuItem.Text = "Удалить";
удалитьToolStripMenuItem.Click += удалитьToolStripMenuItem_Click;
//
// отчетыToolStripMenuItem
//
отчетыToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { документСАватарамиToolStripMenuItem, документСТаблицейToolStripMenuItem, документСГистограммойToolStripMenuItem });
отчетыToolStripMenuItem.Name = "отчетыToolStripMenuItem";
отчетыToolStripMenuItem.Size = new Size(73, 24);
отчетыToolStripMenuItem.Text = "Отчеты";
//
// документСАватарамиToolStripMenuItem
//
документСАватарамиToolStripMenuItem.Name = окументСАватарамиToolStripMenuItem";
документСАватарамиToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.S;
документСАватарамиToolStripMenuItem.Size = new Size(325, 26);
документСАватарамиToolStripMenuItem.Text = "Документ с аватарами";
документСАватарамиToolStripMenuItem.Click += документСАватарамиToolStripMenuItem_Click;
//
// документСТаблицейToolStripMenuItem
//
документСТаблицейToolStripMenuItem.Name = окументСТаблицейToolStripMenuItem";
документСТаблицейToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.T;
документСТаблицейToolStripMenuItem.Size = new Size(325, 26);
документСТаблицейToolStripMenuItem.Text = "Документ с таблицей";
документСТаблицейToolStripMenuItem.Click += документСТаблицейToolStripMenuItem_Click;
//
// документСГистограммойToolStripMenuItem
//
документСГистограммойToolStripMenuItem.Name = окументСГистограммойToolStripMenuItem";
документСГистограммойToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.C;
документСГистограммойToolStripMenuItem.Size = new Size(325, 26);
документСГистограммойToolStripMenuItem.Text = "Документ с гистограммой";
документСГистограммойToolStripMenuItem.Click += документСГистограммойToolStripMenuItem_Click;
//
// интересыToolStripMenuItem
//
интересыToolStripMenuItem.Name = "интересыToolStripMenuItem";
интересыToolStripMenuItem.Size = new Size(92, 24);
интересыToolStripMenuItem.Text = "Интересы";
интересыToolStripMenuItem.Click += интересыToolStripMenuItem_Click;
//
// customDataGridViewTable
//
customDataGridViewTable.Location = new Point(12, 44);
customDataGridViewTable.Margin = new Padding(3, 4, 3, 4);
customDataGridViewTable.Name = "customDataGridViewTable";
customDataGridViewTable.Size = new Size(776, 382);
customDataGridViewTable.TabIndex = 1;
//
// FormMain
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(customDataGridViewTable);
Controls.Add(menuStrip1);
MainMenuStrip = menuStrip1;
Name = "FormMain";
Text = "FormMain";
Load += FormMain_Load;
menuStrip1.ResumeLayout(false);
menuStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private MenuStrip menuStrip1;
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 Components.CustomDataGridView customDataGridViewTable;
private ToolStripMenuItem интересыToolStripMenuItem;
private PutincevLibrary.ComponentExcelWithImage componentExcelWithImage;
private RodionovLibrary.NonVisualComponents.WordTableComponent wordTableComponent;
private Components.NonVisual.HistogramPDF histogrampdf;
}
}

View File

@ -0,0 +1,248 @@
using Components.SaveToPdfHelpers;
using DocumentFormat.OpenXml.Spreadsheet;
using PdfSharp.Pdf.Advanced;
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.ViewModels;
using RodionovLibrary.NonVisualComponents;
using RodionovLibrary.NonVisualComponents.HelperModels;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace PortalAccountsView
{
public partial class FormMain : Form
{
public readonly IAccountLogic _logic;
public readonly IInterestLogic _interestlogic;
public FormMain(IAccountLogic logic, IInterestLogic interestlogic)
{
InitializeComponent();
_logic = logic;
var accounts = new List<(string, string, float)> {
("Идентификатор", "Id", 1),
("Логин", "Login", 1),
("Интерес", "InterestName", 2),
("Почта", "Email", 2)
};
customDataGridViewTable.ConfigureColumns(accounts);
_interestlogic = interestlogic;
}
private void LoadData()
{
var accounts = _logic.ReadList(null);
customDataGridViewTable.FillData(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 FormMain_Load(object sender, EventArgs e)
{
LoadData();
}
private void интересыToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormInterests));
if (service is FormInterests form)
{
form.ShowDialog();
}
}
private void документСАватарамиToolStripMenuItem_Click(object sender, EventArgs e)
{
string fileName = "";
using (var dialog = new SaveFileDialog { Filter = "Excel Files|*.xlsx" })
{
if (dialog.ShowDialog() == DialogResult.OK)
{
fileName = dialog.FileName.ToString();
MessageBox.Show("Файл выбран", "Успех", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else return;
}
List<string> images = new List<string>();
var list = _logic.ReadList(null);
try
{
if (list != null)
{
foreach (var item in list)
{
images.Add(item.AvatarPath);
}
string[] imagesArray = images.ToArray();
componentExcelWithImage.CreateExcelWithImages(fileName, "Сканы чеков", imagesArray);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка");
}
}
private void редактироватьToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormAccount));
if (service is FormAccount form)
{
var selected = customDataGridViewTable.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 = customDataGridViewTable.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)
{
string fileName = "";
using (var dialog = new SaveFileDialog { Filter = "docx|*.docx" })
{
if (dialog.ShowDialog() == DialogResult.OK)
{
fileName = dialog.FileName.ToString();
MessageBox.Show("Файл выбран", "Успех", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else return;
}
string title = "Документ с таблицей";
var mergedColumns = new List<(int, int)>
{
(1, 2),
};
var columns = new List<ColumnParameters>
{
new() { FirstRowHeader = "Идент", PropertyName = "Id", Width = 1.3 },
new() { FirstRowHeader = "Личные данные", SecondRowHeader = "Логин", PropertyName = "Login", Width = 1.7 },
new() { FirstRowHeader = "Личные данные", SecondRowHeader = "Почта", PropertyName = "Email", Width = 1.7 },
new() { FirstRowHeader = "Интерес", PropertyName = "InterestName", Width = 1.7 },
};
var list = _logic.ReadList(null);
var tableInfo = new WordTableInfo<AccountViewModel>
{
FileName = fileName,
Title = title,
ColumnParameters = columns,
Items = list,
MergedColumns = mergedColumns
};
try
{
wordTableComponent.CreateTable(tableInfo);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка");
}
}
private void документСГистограммойToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
string fileName = "";
using (var dialog = new SaveFileDialog { Filter = "pdf|*.pdf" })
{
if (dialog.ShowDialog() == DialogResult.OK)
{
fileName = dialog.FileName.ToString();
MessageBox.Show("Файл выбран", "Успех", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else return;
}
var accounts = _logic.ReadList(null);
var list = new ChartData();
var groupedAccounts = accounts.GroupBy(account => account.InterestName)
.Select(group => new
{
InterestName = group.Key,
AccountCount = group.Count()
})
.ToList();
var data = new Dictionary<string, double>();
foreach (var group in groupedAccounts)
{
data.Add(group.InterestName, (double)group.AccountCount);
}
list.Data= data;
list.SeriesName = "Пользователи";
var acc = new List<ChartData>();
acc.Add(list);
var histogrammInfo = new HistogramData
{
FilePath = fileName,
DocumentTitle = "Гистограмма PDF",
ChartTitle = "Количетсво интересов у пользователей",
LegendPosition = LegendPositions.Bottom,
ChartData = acc,
};
try
{
histogrampdf.CreateHistogramPdf(histogrammInfo);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка");
}
}
}
}

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="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="componentExcelWithImage.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>153, 17</value>
</metadata>
<metadata name="wordTableComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>400, 17</value>
</metadata>
<metadata name="histogrampdf.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>611, 17</value>
</metadata>
</root>

View File

@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Components" Version="1.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.11" />
<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="RodionovLibrary" Version="1.0.0" />
<PackageReference Include="System.Text.Encodings.Web" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsBusinessLogic\PortalAccountsBusinessLogic.csproj" />
<ProjectReference Include="..\PortalAccountsContracts\PortalAccountsContracts.csproj" />
<ProjectReference Include="..\PortalAccountsDatabaseImplement\PortalAccountsDatabaseImplement.csproj" />
<ProjectReference Include="..\PortalAccountsDataModels\PortalAccountsDataModels.csproj" />
<ProjectReference Include="..\PutincevLibrary\PutincevLibrary.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,40 @@
using Microsoft.Extensions.DependencyInjection;
using PortalAccountsBusinessLogic.BusinessLogics;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsDatabaseImplement.Implements;
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<IInterestStorage, InterestStorage>();
services.AddTransient<IAccountStorage, AccountStorage>();
services.AddTransient<IInterestLogic, InterestLogic>();
services.AddTransient<IAccountLogic, AccountLogic>();
services.AddTransient<FormMain>();
services.AddTransient<FormAccount>();
services.AddTransient<FormInterests>();
}
}
}

View File

@ -6,6 +6,7 @@
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>