diff --git a/COP/COP.sln b/COP/COP.sln index b1d5ede..d90f173 100644 --- a/COP/COP.sln +++ b/COP/COP.sln @@ -3,9 +3,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.10.35004.147 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 -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 Global 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}.Release|Any CPU.ActiveCfg = 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 GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/COP/PortalAccountsBusinessLogic/BusinessLogics/AccountLogic.cs b/COP/PortalAccountsBusinessLogic/BusinessLogics/AccountLogic.cs new file mode 100644 index 0000000..2c242f1 --- /dev/null +++ b/COP/PortalAccountsBusinessLogic/BusinessLogics/AccountLogic.cs @@ -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? 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("Аккаунт с таким логином уже есть"); + } + } + } +} \ No newline at end of file diff --git a/COP/PortalAccountsBusinessLogic/BusinessLogics/InterestLogic.cs b/COP/PortalAccountsBusinessLogic/BusinessLogics/InterestLogic.cs new file mode 100644 index 0000000..c73ea04 --- /dev/null +++ b/COP/PortalAccountsBusinessLogic/BusinessLogics/InterestLogic.cs @@ -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? 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("Интерес с таким названием уже есть"); + } + } + } +} \ No newline at end of file diff --git a/COP/PortalAccountsBusinessLogic/PortalAccountsBusinessLogic.csproj b/COP/PortalAccountsBusinessLogic/PortalAccountsBusinessLogic.csproj new file mode 100644 index 0000000..5691a38 --- /dev/null +++ b/COP/PortalAccountsBusinessLogic/PortalAccountsBusinessLogic.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/COP/PortalAccountsContracts/BindingModels/AccountBindingModel.cs b/COP/PortalAccountsContracts/BindingModels/AccountBindingModel.cs new file mode 100644 index 0000000..87da6f4 --- /dev/null +++ b/COP/PortalAccountsContracts/BindingModels/AccountBindingModel.cs @@ -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; } + } +} diff --git a/COP/PortalAccountsContracts/BindingModels/InterestBindingModel.cs b/COP/PortalAccountsContracts/BindingModels/InterestBindingModel.cs new file mode 100644 index 0000000..267ae1a --- /dev/null +++ b/COP/PortalAccountsContracts/BindingModels/InterestBindingModel.cs @@ -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; + } +} diff --git a/COP/PortalAccountsContracts/BusinessLogicsContracts/IAccountLogic.cs b/COP/PortalAccountsContracts/BusinessLogicsContracts/IAccountLogic.cs new file mode 100644 index 0000000..1d3418a --- /dev/null +++ b/COP/PortalAccountsContracts/BusinessLogicsContracts/IAccountLogic.cs @@ -0,0 +1,19 @@ +using PortalAccountsContracts.BindingModels; +using PortalAccountsContracts.SearchModels; +using PortalAccountsContracts.ViewModels; + +namespace PortalAccountsContracts.BusinessLogicsContracts +{ + public interface IAccountLogic + { + List? ReadList(AccountSearchModel? model); + + AccountViewModel? ReadElement(AccountSearchModel model); + + bool Create(AccountBindingModel model); + + bool Update(AccountBindingModel model); + + bool Delete(AccountBindingModel model); + } +} \ No newline at end of file diff --git a/COP/PortalAccountsContracts/BusinessLogicsContracts/IInterestLogic.cs b/COP/PortalAccountsContracts/BusinessLogicsContracts/IInterestLogic.cs new file mode 100644 index 0000000..975bb19 --- /dev/null +++ b/COP/PortalAccountsContracts/BusinessLogicsContracts/IInterestLogic.cs @@ -0,0 +1,19 @@ +using PortalAccountsContracts.BindingModels; +using PortalAccountsContracts.SearchModels; +using PortalAccountsContracts.ViewModels; + +namespace PortalAccountsContracts.BusinessLogicsContracts +{ + public interface IInterestLogic + { + List? ReadList(InterestSearchModel? model); + + InterestViewModel? ReadElement(InterestSearchModel model); + + bool Create(InterestBindingModel model); + + bool Update(InterestBindingModel model); + + bool Delete(InterestBindingModel model); + } +} \ No newline at end of file diff --git a/COP/PortalAccountsContracts/PortalAccountsContracts.csproj b/COP/PortalAccountsContracts/PortalAccountsContracts.csproj new file mode 100644 index 0000000..a92b076 --- /dev/null +++ b/COP/PortalAccountsContracts/PortalAccountsContracts.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/COP/PortalAccountsContracts/SearchModels/AccountSearchModel.cs b/COP/PortalAccountsContracts/SearchModels/AccountSearchModel.cs new file mode 100644 index 0000000..3edfddf --- /dev/null +++ b/COP/PortalAccountsContracts/SearchModels/AccountSearchModel.cs @@ -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; } + } +} diff --git a/COP/PortalAccountsContracts/SearchModels/InterestSearchModel.cs b/COP/PortalAccountsContracts/SearchModels/InterestSearchModel.cs new file mode 100644 index 0000000..b282504 --- /dev/null +++ b/COP/PortalAccountsContracts/SearchModels/InterestSearchModel.cs @@ -0,0 +1,9 @@ +namespace PortalAccountsContracts.SearchModels +{ + public class InterestSearchModel + { + public int? Id { get; set; } + + public string? Name { get; set; } + } +} diff --git a/COP/PortalAccountsContracts/StoragesContracts/IAccountStorage.cs b/COP/PortalAccountsContracts/StoragesContracts/IAccountStorage.cs new file mode 100644 index 0000000..dfd9845 --- /dev/null +++ b/COP/PortalAccountsContracts/StoragesContracts/IAccountStorage.cs @@ -0,0 +1,21 @@ +using PortalAccountsContracts.BindingModels; +using PortalAccountsContracts.SearchModels; +using PortalAccountsContracts.ViewModels; + +namespace PortalAccountsContracts.StoragesContracts +{ + public interface IAccountStorage + { + List GetFullList(); + + List GetFilteredList(AccountSearchModel model); + + AccountViewModel? GetElement(AccountSearchModel model); + + AccountViewModel? Insert(AccountBindingModel model); + + AccountViewModel? Update(AccountBindingModel model); + + AccountViewModel? Delete(AccountBindingModel model); + } +} \ No newline at end of file diff --git a/COP/PortalAccountsContracts/StoragesContracts/IInterestStorage.cs b/COP/PortalAccountsContracts/StoragesContracts/IInterestStorage.cs new file mode 100644 index 0000000..aa4b8f1 --- /dev/null +++ b/COP/PortalAccountsContracts/StoragesContracts/IInterestStorage.cs @@ -0,0 +1,21 @@ +using PortalAccountsContracts.BindingModels; +using PortalAccountsContracts.SearchModels; +using PortalAccountsContracts.ViewModels; + +namespace PortalAccountsContracts.StoragesContracts +{ + public interface IInterestStorage + { + List GetFullList(); + + List GetFilteredList(InterestSearchModel model); + + InterestViewModel? GetElement(InterestSearchModel model); + + InterestViewModel? Insert(InterestBindingModel model); + + InterestViewModel? Update(InterestBindingModel model); + + InterestViewModel? Delete(InterestBindingModel model); + } +} \ No newline at end of file diff --git a/COP/PortalAccountsContracts/ViewModels/AccountViewModel.cs b/COP/PortalAccountsContracts/ViewModels/AccountViewModel.cs new file mode 100644 index 0000000..9e0bfbd --- /dev/null +++ b/COP/PortalAccountsContracts/ViewModels/AccountViewModel.cs @@ -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; } + + } +} diff --git a/COP/PortalAccountsContracts/ViewModels/InterestViewModel.cs b/COP/PortalAccountsContracts/ViewModels/InterestViewModel.cs new file mode 100644 index 0000000..7448263 --- /dev/null +++ b/COP/PortalAccountsContracts/ViewModels/InterestViewModel.cs @@ -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; + } +} diff --git a/COP/PortalAccountsDataModels/IId.cs b/COP/PortalAccountsDataModels/IId.cs new file mode 100644 index 0000000..d745687 --- /dev/null +++ b/COP/PortalAccountsDataModels/IId.cs @@ -0,0 +1,7 @@ +namespace PortalAccountsDataModels +{ + public interface IId + { + int Id { get; } + } +} \ No newline at end of file diff --git a/COP/PortalAccountsDataModels/Models/IAccountModel.cs b/COP/PortalAccountsDataModels/Models/IAccountModel.cs new file mode 100644 index 0000000..fab4449 --- /dev/null +++ b/COP/PortalAccountsDataModels/Models/IAccountModel.cs @@ -0,0 +1,13 @@ +namespace PortalAccountsDataModels.Models +{ + public interface IAccountModel : IId + { + string Login { get; } + + string? AvatarPath { get; } + + int InterestId { get; } + + string? Email { get; } + } +} diff --git a/COP/PortalAccountsDataModels/Models/IInterestModel.cs b/COP/PortalAccountsDataModels/Models/IInterestModel.cs new file mode 100644 index 0000000..591dd03 --- /dev/null +++ b/COP/PortalAccountsDataModels/Models/IInterestModel.cs @@ -0,0 +1,7 @@ +namespace PortalAccountsDataModels.Models +{ + public interface IInterestModel : IId + { + string Name { get; } + } +} diff --git a/COP/PortalAccountsDataModels/PortalAccountsDataModels.csproj b/COP/PortalAccountsDataModels/PortalAccountsDataModels.csproj new file mode 100644 index 0000000..132c02c --- /dev/null +++ b/COP/PortalAccountsDataModels/PortalAccountsDataModels.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/COP/PortalAccountsDatabaseImplement/Implements/AccountStorage.cs b/COP/PortalAccountsDatabaseImplement/Implements/AccountStorage.cs new file mode 100644 index 0000000..cc614bc --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/Implements/AccountStorage.cs @@ -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 GetFullList() + { + using var context = new PortalAccountsDatabase(); + return context.Accounts + .Include(x => x.Interest) + .Select(x => x.GetViewModel) + .ToList(); + } + + public List 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; + } + } +} \ No newline at end of file diff --git a/COP/PortalAccountsDatabaseImplement/Implements/InterestStorage.cs b/COP/PortalAccountsDatabaseImplement/Implements/InterestStorage.cs new file mode 100644 index 0000000..5e1ac45 --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/Implements/InterestStorage.cs @@ -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 GetFullList() + { + using var context = new PortalAccountsDatabase(); + return context.Interests + .Select(x => x.GetViewModel) + .ToList(); + } + + public List 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; + } + } +} diff --git a/COP/PortalAccountsDatabaseImplement/Migrations/20241106113420_migr.Designer.cs b/COP/PortalAccountsDatabaseImplement/Migrations/20241106113420_migr.Designer.cs new file mode 100644 index 0000000..6816d8f --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/Migrations/20241106113420_migr.Designer.cs @@ -0,0 +1,90 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvatarPath") + .HasColumnType("text"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("InterestId") + .HasColumnType("integer"); + + b.Property("Login") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("InterestId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("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 + } + } +} diff --git a/COP/PortalAccountsDatabaseImplement/Migrations/20241106113420_migr.cs b/COP/PortalAccountsDatabaseImplement/Migrations/20241106113420_migr.cs new file mode 100644 index 0000000..3b356af --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/Migrations/20241106113420_migr.cs @@ -0,0 +1,65 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace PortalAccountsDatabaseImplement.Migrations +{ + /// + public partial class migr : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Interests", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Interests", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Accounts", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Login = table.Column(type: "text", nullable: false), + AvatarPath = table.Column(type: "text", nullable: true), + InterestId = table.Column(type: "integer", nullable: false), + Email = table.Column(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"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Accounts"); + + migrationBuilder.DropTable( + name: "Interests"); + } + } +} diff --git a/COP/PortalAccountsDatabaseImplement/Migrations/PortalAccountsDatabaseModelSnapshot.cs b/COP/PortalAccountsDatabaseImplement/Migrations/PortalAccountsDatabaseModelSnapshot.cs new file mode 100644 index 0000000..fb7e9f5 --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/Migrations/PortalAccountsDatabaseModelSnapshot.cs @@ -0,0 +1,87 @@ +// +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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvatarPath") + .HasColumnType("text"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("InterestId") + .HasColumnType("integer"); + + b.Property("Login") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("InterestId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("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 + } + } +} diff --git a/COP/PortalAccountsDatabaseImplement/Models/Account.cs b/COP/PortalAccountsDatabaseImplement/Models/Account.cs new file mode 100644 index 0000000..09417c8 --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/Models/Account.cs @@ -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 + }; + } +} diff --git a/COP/PortalAccountsDatabaseImplement/Models/Interest.cs b/COP/PortalAccountsDatabaseImplement/Models/Interest.cs new file mode 100644 index 0000000..e95323d --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/Models/Interest.cs @@ -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 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 + }; + } +} + diff --git a/COP/PortalAccountsDatabaseImplement/PortalAccountsDatabase.cs b/COP/PortalAccountsDatabaseImplement/PortalAccountsDatabase.cs new file mode 100644 index 0000000..657f727 --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/PortalAccountsDatabase.cs @@ -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 Accounts { set; get; } + + public virtual DbSet Interests { set; get; } + } +} \ No newline at end of file diff --git a/COP/PortalAccountsDatabaseImplement/PortalAccountsDatabaseImplement.csproj b/COP/PortalAccountsDatabaseImplement/PortalAccountsDatabaseImplement.csproj new file mode 100644 index 0000000..16b48f4 --- /dev/null +++ b/COP/PortalAccountsDatabaseImplement/PortalAccountsDatabaseImplement.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/COP/PortalAccountsView/FormAccount.Designer.cs b/COP/PortalAccountsView/FormAccount.Designer.cs new file mode 100644 index 0000000..5cb3df5 --- /dev/null +++ b/COP/PortalAccountsView/FormAccount.Designer.cs @@ -0,0 +1,169 @@ +namespace PortalAccountsView +{ + partial class FormAccount + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} \ No newline at end of file diff --git a/COP/PortalAccountsView/FormAccount.cs b/COP/PortalAccountsView/FormAccount.cs new file mode 100644 index 0000000..c0f34c9 --- /dev/null +++ b/COP/PortalAccountsView/FormAccount.cs @@ -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 _interests; + + public int Id { set { _id = value; } } + public FormAccount(IAccountLogic logic, IInterestLogic interestLogic) + { + InitializeComponent(); + _logic = logic; + _interestLogic = interestLogic; + _interests = new List(); + 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(); + } + } + } + } +} diff --git a/COP/PortalAccountsView/FormAccount.resx b/COP/PortalAccountsView/FormAccount.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/COP/PortalAccountsView/FormAccount.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/COP/PortalAccountsView/FormInterests.Designer.cs b/COP/PortalAccountsView/FormInterests.Designer.cs new file mode 100644 index 0000000..45bff2e --- /dev/null +++ b/COP/PortalAccountsView/FormInterests.Designer.cs @@ -0,0 +1,87 @@ +namespace PortalAccountsView +{ + partial class FormInterests + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} \ No newline at end of file diff --git a/COP/PortalAccountsView/FormInterests.cs b/COP/PortalAccountsView/FormInterests.cs new file mode 100644 index 0000000..63256e4 --- /dev/null +++ b/COP/PortalAccountsView/FormInterests.cs @@ -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); + } + } +} diff --git a/COP/PortalAccountsView/FormInterests.resx b/COP/PortalAccountsView/FormInterests.resx new file mode 100644 index 0000000..91e09cb --- /dev/null +++ b/COP/PortalAccountsView/FormInterests.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/COP/PortalAccountsView/FormMain.Designer.cs b/COP/PortalAccountsView/FormMain.Designer.cs new file mode 100644 index 0000000..55a3216 --- /dev/null +++ b/COP/PortalAccountsView/FormMain.Designer.cs @@ -0,0 +1,171 @@ +namespace PortalAccountsView +{ + partial class FormMain + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} \ No newline at end of file diff --git a/COP/PortalAccountsView/FormMain.cs b/COP/PortalAccountsView/FormMain.cs new file mode 100644 index 0000000..9e80976 --- /dev/null +++ b/COP/PortalAccountsView/FormMain.cs @@ -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 images = new List(); + 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(); + 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(); + 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 + { + 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 + { + 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(); + + foreach (var group in groupedAccounts) + { + data.Add(group.InterestName, (double)group.AccountCount); + } + + list.Data= data; + list.SeriesName = "Пользователи"; + var acc = new List(); + + 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, "Ошибка"); + } + } + } +} diff --git a/COP/PortalAccountsView/FormMain.resx b/COP/PortalAccountsView/FormMain.resx new file mode 100644 index 0000000..703651c --- /dev/null +++ b/COP/PortalAccountsView/FormMain.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 153, 17 + + + 400, 17 + + + 611, 17 + + \ No newline at end of file diff --git a/COP/PortalAccountsView/PortalAccountsView.csproj b/COP/PortalAccountsView/PortalAccountsView.csproj new file mode 100644 index 0000000..c4e6db9 --- /dev/null +++ b/COP/PortalAccountsView/PortalAccountsView.csproj @@ -0,0 +1,32 @@ + + + + WinExe + net8.0-windows7.0 + enable + true + enable + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/COP/PortalAccountsView/Program.cs b/COP/PortalAccountsView/Program.cs new file mode 100644 index 0000000..07ff5c6 --- /dev/null +++ b/COP/PortalAccountsView/Program.cs @@ -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 + { + /// + /// The main entry point for the application. + /// + + 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()); + } + + private static void ConfigureServices(ServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + } + } +} \ No newline at end of file diff --git a/COP/PutincevLibrary/PutincevLibrary.csproj b/COP/PutincevLibrary/PutincevLibrary.csproj index 3684330..1d78ed7 100644 --- a/COP/PutincevLibrary/PutincevLibrary.csproj +++ b/COP/PutincevLibrary/PutincevLibrary.csproj @@ -6,6 +6,7 @@ true enable Library + True