Refactored service provider usage
- Remove service provider from WinForms altogether - Moved service provider handling to processors
This commit is contained in:
parent
f49f6079d5
commit
36a8efb05d
@ -1,6 +1,7 @@
|
|||||||
using DataModel.Database;
|
using DataModel.Database;
|
||||||
using DataModel.Database.Common;
|
using DataModel.Database.Common;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Processor;
|
namespace Processor;
|
||||||
|
|
||||||
@ -9,16 +10,24 @@ public static class SectionProcessor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load one layer of the tree by using the specified depth:
|
/// Load one layer of the tree by using the specified depth:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IAsyncEnumerable<Section> LoadLayer(DataContext db, int depth)
|
public static async Task<List<Section>> LoadLayer(int depth)
|
||||||
{
|
{
|
||||||
return db.Sections.Where(n => n.Depth == depth).OrderBy(n => n.Id).AsAsyncEnumerable();
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
var sections = await db.Sections.Where(n => n.Depth == depth).OrderBy(n => n.Id).ToListAsync();
|
||||||
|
|
||||||
|
// Ensure, that the database loaded the section's parent:
|
||||||
|
foreach (var section in sections)
|
||||||
|
await db.Entry(section).Reference(n => n.Parent).LoadAsync();
|
||||||
|
|
||||||
|
return sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determine how deep the tree is.
|
/// Determine how deep the tree is.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async ValueTask<int> GetDepth(DataContext db)
|
public static async ValueTask<int> GetDepth()
|
||||||
{
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
if(!await db.Sections.AnyAsync())
|
if(!await db.Sections.AnyAsync())
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -30,8 +39,10 @@ public static class SectionProcessor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compute the new sections key and its depth, then store the section in the database.
|
/// Compute the new sections key and its depth, then store the section in the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task<ProcessorResult<Section>> AddSection(DataContext db, string text, string? parentKey)
|
public static async Task<ProcessorResult<Section>> AddSection(string text, string? parentKey)
|
||||||
{
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
|
||||||
// Remove any whitespaces from the section name, regardless of how many e.g. spaces the user typed:
|
// Remove any whitespaces from the section name, regardless of how many e.g. spaces the user typed:
|
||||||
var key = string.Join('_', text.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant();
|
var key = string.Join('_', text.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant();
|
||||||
|
|
||||||
@ -97,24 +108,32 @@ public static class SectionProcessor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task RemoveSection(DataContext db, string selectedKey)
|
public static async Task RemoveSection(string selectedKey)
|
||||||
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
await SectionProcessor.RemoveOneSectionAndItsChildren(db, selectedKey);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task RemoveOneSectionAndItsChildren(DataContext db, string selectedKey)
|
||||||
{
|
{
|
||||||
// Remove the section from the database:
|
// Remove the section from the database:
|
||||||
var section2Delete = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey);
|
var section2Delete = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey);
|
||||||
if (section2Delete is null)
|
if (section2Delete is null)
|
||||||
throw new ArgumentException($"The section with key {selectedKey} does not exist in the database.");
|
throw new ArgumentException($"The section with key {selectedKey} does not exist in the database.");
|
||||||
|
|
||||||
// Next, remove all children of the section, and the children's children, etc.:
|
// Next, remove all children of the section, and the children's children, etc.:
|
||||||
var children = await db.Sections.Where(n => n.Parent == section2Delete).ToListAsync();
|
var children = await db.Sections.Where(n => n.Parent == section2Delete).ToListAsync();
|
||||||
foreach (var child in children)
|
foreach (var child in children)
|
||||||
await RemoveSection(db, child.DataKey);
|
await SectionProcessor.RemoveOneSectionAndItsChildren(db, child.DataKey);
|
||||||
|
|
||||||
db.Sections.Remove(section2Delete);
|
db.Sections.Remove(section2Delete);
|
||||||
await db.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<int> NumberChildren(DataContext db, string selectedKey)
|
public static async Task<int> NumberChildren(string selectedKey)
|
||||||
{
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
|
||||||
// Read the section from the database:
|
// Read the section from the database:
|
||||||
var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey);
|
var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey);
|
||||||
if (section is null)
|
if (section is null)
|
||||||
@ -123,8 +142,10 @@ public static class SectionProcessor
|
|||||||
return await db.Sections.CountAsync(n => n.Parent == section);
|
return await db.Sections.CountAsync(n => n.Parent == section);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<ProcessorResult<Section>> RenameSection(DataContext db, string selectedNodeKey, string alteredName)
|
public static async Task<ProcessorResult<Section>> RenameSection(string selectedNodeKey, string alteredName)
|
||||||
{
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
|
||||||
// Read the section from the database:
|
// Read the section from the database:
|
||||||
var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedNodeKey);
|
var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedNodeKey);
|
||||||
if (section is null)
|
if (section is null)
|
||||||
@ -158,10 +179,18 @@ public static class SectionProcessor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Section GetSection(DataContext db, string sectionKey) => db.Sections.First(n => n.DataKey == sectionKey);
|
public static async Task<Section> GetSection(string sectionKey)
|
||||||
|
|
||||||
public static async Task<string> GetSectionPath(DataContext db, string sectionKey)
|
|
||||||
{
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey);
|
||||||
|
await db.Entry(section).Reference(n => n.Parent).LoadAsync();
|
||||||
|
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<string> GetSectionPath(string sectionKey)
|
||||||
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey);
|
var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey);
|
||||||
|
|
||||||
// Ensure, that the database loaded the section's parent:
|
// Ensure, that the database loaded the section's parent:
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
using DataModel.Database;
|
using DataModel.Database;
|
||||||
using DataModel.Database.Common;
|
using DataModel.Database.Common;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Processor;
|
namespace Processor;
|
||||||
|
|
||||||
public static class TextElementProcessor
|
public static class TextElementProcessor
|
||||||
{
|
{
|
||||||
public static Task<IAsyncEnumerable<TextElement>> GetTextElements(DataContext db, Section section)
|
public static async Task<List<TextElement>> GetTextElements(Section section)
|
||||||
{
|
{
|
||||||
return Task.FromResult(db.TextElements.Where(n => n.Section == section).AsAsyncEnumerable());
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
return await db.TextElements.Where(n => n.Section == section).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<ProcessorResult<TextElement>> AddTextElement(DataContext db, string? currentSectionKey, string elementName)
|
public static async Task<ProcessorResult<TextElement>> AddTextElement(string? currentSectionKey, string elementName)
|
||||||
{
|
{
|
||||||
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
|
||||||
if(string.IsNullOrWhiteSpace(currentSectionKey))
|
if(string.IsNullOrWhiteSpace(currentSectionKey))
|
||||||
throw new ArgumentOutOfRangeException(nameof(currentSectionKey));
|
throw new ArgumentOutOfRangeException(nameof(currentSectionKey));
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using DataModel.Database.Common;
|
using Processor;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Processor;
|
|
||||||
using UI_WinForms.Dialogs;
|
using UI_WinForms.Dialogs;
|
||||||
using UI_WinForms.Resources;
|
using UI_WinForms.Resources;
|
||||||
|
|
||||||
@ -8,8 +6,6 @@ namespace UI_WinForms.Components;
|
|||||||
|
|
||||||
public partial class SectionTree : UserControl
|
public partial class SectionTree : UserControl
|
||||||
{
|
{
|
||||||
private readonly DataContext db;
|
|
||||||
|
|
||||||
public SectionTree()
|
public SectionTree()
|
||||||
{
|
{
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
@ -18,12 +14,6 @@ public partial class SectionTree : UserControl
|
|||||||
if(Program.SERVICE_PROVIDER is null)
|
if(Program.SERVICE_PROVIDER is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get the DI context from the main form:
|
|
||||||
this.db = Program.SERVICE_PROVIDER.GetService<DataContext>()!;
|
|
||||||
|
|
||||||
// Dispose of the context when the control is disposed:
|
|
||||||
this.Disposed += (_, _) => this.db.Dispose();
|
|
||||||
|
|
||||||
// Create an image list from a resource:
|
// Create an image list from a resource:
|
||||||
var imgList = new ImageList();
|
var imgList = new ImageList();
|
||||||
imgList.ImageSize = new Size(45, 45);
|
imgList.ImageSize = new Size(45, 45);
|
||||||
@ -46,7 +36,7 @@ public partial class SectionTree : UserControl
|
|||||||
var treeNodes = new Dictionary<string, TreeNode>();
|
var treeNodes = new Dictionary<string, TreeNode>();
|
||||||
|
|
||||||
// Get the max. depth of the tree:
|
// Get the max. depth of the tree:
|
||||||
var maxDepth = await SectionProcessor.GetDepth(this.db);
|
var maxDepth = await SectionProcessor.GetDepth();
|
||||||
|
|
||||||
// Store nodes, where we cannot find the parents:
|
// Store nodes, where we cannot find the parents:
|
||||||
var missingParents = new List<TreeNode>();
|
var missingParents = new List<TreeNode>();
|
||||||
@ -54,7 +44,7 @@ public partial class SectionTree : UserControl
|
|||||||
// Populate the tree view out of the database, layer by layer:
|
// Populate the tree view out of the database, layer by layer:
|
||||||
for (var i = 0; i <= maxDepth; i++)
|
for (var i = 0; i <= maxDepth; i++)
|
||||||
{
|
{
|
||||||
await foreach (var section in SectionProcessor.LoadLayer(this.db, i))
|
foreach (var section in await SectionProcessor.LoadLayer(i))
|
||||||
{
|
{
|
||||||
// Create the tree node:
|
// Create the tree node:
|
||||||
var node = new TreeNode
|
var node = new TreeNode
|
||||||
@ -139,7 +129,7 @@ public partial class SectionTree : UserControl
|
|||||||
var selectedNode = this.treeView.SelectedNode;
|
var selectedNode = this.treeView.SelectedNode;
|
||||||
|
|
||||||
// Add the new section to the database:
|
// Add the new section to the database:
|
||||||
var addedSection = await SectionProcessor.AddSection(this.db, result.Text, addRootNode ? null : selectedNode?.Name);
|
var addedSection = await SectionProcessor.AddSection(result.Text, addRootNode ? null : selectedNode?.Name);
|
||||||
|
|
||||||
addedSection.ProcessError();
|
addedSection.ProcessError();
|
||||||
if(!addedSection.Successful)
|
if(!addedSection.Successful)
|
||||||
@ -173,7 +163,7 @@ public partial class SectionTree : UserControl
|
|||||||
|
|
||||||
// Get the number of children:
|
// Get the number of children:
|
||||||
// (notice, that the node's name is its key)
|
// (notice, that the node's name is its key)
|
||||||
var numberChildren = await SectionProcessor.NumberChildren(this.db, selectedNode.Name);
|
var numberChildren = await SectionProcessor.NumberChildren(selectedNode.Name);
|
||||||
|
|
||||||
// Ask the user, if he really wants to remove the section:
|
// Ask the user, if he really wants to remove the section:
|
||||||
if(MessageBox.Show(numberChildren > 0 ? $"Are you sure, you want to remove the section '{selectedNode.Text}', its {numberChildren} children and so on?" : $"Are you sure, you want to remove the section '{selectedNode.Text}'?", "Remove section", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
|
if(MessageBox.Show(numberChildren > 0 ? $"Are you sure, you want to remove the section '{selectedNode.Text}', its {numberChildren} children and so on?" : $"Are you sure, you want to remove the section '{selectedNode.Text}'?", "Remove section", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
|
||||||
@ -181,7 +171,7 @@ public partial class SectionTree : UserControl
|
|||||||
|
|
||||||
// Remove the section from the database:
|
// Remove the section from the database:
|
||||||
// (notice, that the node's name is its key)
|
// (notice, that the node's name is its key)
|
||||||
await SectionProcessor.RemoveSection(this.db, selectedNode.Name);
|
await SectionProcessor.RemoveSection(selectedNode.Name);
|
||||||
|
|
||||||
// Remove all nodes from the tree control:
|
// Remove all nodes from the tree control:
|
||||||
this.treeView.Nodes.Clear();
|
this.treeView.Nodes.Clear();
|
||||||
@ -190,7 +180,7 @@ public partial class SectionTree : UserControl
|
|||||||
this.LoadNodes(this, EventArgs.Empty);
|
this.LoadNodes(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
|
private async void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
|
||||||
{
|
{
|
||||||
if(this.DesignMode)
|
if(this.DesignMode)
|
||||||
return;
|
return;
|
||||||
@ -205,7 +195,7 @@ public partial class SectionTree : UserControl
|
|||||||
if (selectedNode is not null)
|
if (selectedNode is not null)
|
||||||
{
|
{
|
||||||
// Get the section from the database:
|
// Get the section from the database:
|
||||||
var section = SectionProcessor.GetSection(this.db, selectedNode.Name);
|
var section = await SectionProcessor.GetSection(selectedNode.Name);
|
||||||
AppEvents.SectionChanged(section);
|
AppEvents.SectionChanged(section);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +225,7 @@ public partial class SectionTree : UserControl
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Rename the section:
|
// Rename the section:
|
||||||
var alteredSection = await SectionProcessor.RenameSection(this.db, selectedNode.Name, result.Text);
|
var alteredSection = await SectionProcessor.RenameSection(selectedNode.Name, result.Text);
|
||||||
|
|
||||||
alteredSection.ProcessError();
|
alteredSection.ProcessError();
|
||||||
if(!alteredSection.Successful)
|
if(!alteredSection.Successful)
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using DataModel.Database;
|
using DataModel.Database;
|
||||||
using DataModel.Database.Common;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Processor;
|
using Processor;
|
||||||
using UI_WinForms.Dialogs;
|
using UI_WinForms.Dialogs;
|
||||||
|
|
||||||
@ -8,8 +6,6 @@ namespace UI_WinForms.Components;
|
|||||||
|
|
||||||
public partial class TextElements : UserControl
|
public partial class TextElements : UserControl
|
||||||
{
|
{
|
||||||
private readonly DataContext db;
|
|
||||||
|
|
||||||
private Section? currentSection;
|
private Section? currentSection;
|
||||||
|
|
||||||
public TextElements()
|
public TextElements()
|
||||||
@ -20,12 +16,6 @@ public partial class TextElements : UserControl
|
|||||||
if(Program.SERVICE_PROVIDER is null)
|
if(Program.SERVICE_PROVIDER is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get the DI context from the main form:
|
|
||||||
this.db = Program.SERVICE_PROVIDER.GetService<DataContext>()!;
|
|
||||||
|
|
||||||
// Dispose of the context when the control is disposed:
|
|
||||||
this.Disposed += (_, _) => this.db.Dispose();
|
|
||||||
|
|
||||||
// When the section is changed, update this component:
|
// When the section is changed, update this component:
|
||||||
AppEvents.WhenSectionChanged += async (sender, section) =>
|
AppEvents.WhenSectionChanged += async (sender, section) =>
|
||||||
{
|
{
|
||||||
@ -36,7 +26,7 @@ public partial class TextElements : UserControl
|
|||||||
if (this.currentSection is null)
|
if (this.currentSection is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.labelSectionPath.Text = await SectionProcessor.GetSectionPath(this.db, this.currentSection.DataKey);
|
this.labelSectionPath.Text = await SectionProcessor.GetSectionPath(this.currentSection.DataKey);
|
||||||
this.LoadTextElements();
|
this.LoadTextElements();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -48,11 +38,11 @@ public partial class TextElements : UserControl
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Load the text elements:
|
// Load the text elements:
|
||||||
var textElements = await TextElementProcessor.GetTextElements(this.db, this.currentSection);
|
var textElements = await TextElementProcessor.GetTextElements(this.currentSection);
|
||||||
|
|
||||||
// Update the list:
|
// Update the list:
|
||||||
this.listTextElements.Items.Clear();
|
this.listTextElements.Items.Clear();
|
||||||
await foreach (var textElement in textElements)
|
foreach (var textElement in textElements)
|
||||||
{
|
{
|
||||||
var item = new ListViewItem(textElement.Name)
|
var item = new ListViewItem(textElement.Name)
|
||||||
{
|
{
|
||||||
@ -79,7 +69,7 @@ public partial class TextElements : UserControl
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Add the text element to the database into the current section:
|
// Add the text element to the database into the current section:
|
||||||
var newTextElement = await TextElementProcessor.AddTextElement(this.db, this.currentSection?.DataKey, result.Text);
|
var newTextElement = await TextElementProcessor.AddTextElement(this.currentSection?.DataKey, result.Text);
|
||||||
newTextElement.ProcessError();
|
newTextElement.ProcessError();
|
||||||
|
|
||||||
if(!newTextElement.Successful)
|
if(!newTextElement.Successful)
|
||||||
|
@ -2,6 +2,7 @@ using DataModel;
|
|||||||
using DataModel.Database.Common;
|
using DataModel.Database.Common;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Processor;
|
||||||
|
|
||||||
namespace UI_WinForms;
|
namespace UI_WinForms;
|
||||||
|
|
||||||
@ -34,9 +35,6 @@ internal static class Program
|
|||||||
//
|
//
|
||||||
builder.ConfigureServices((hostContext, serviceCollection) =>
|
builder.ConfigureServices((hostContext, serviceCollection) =>
|
||||||
{
|
{
|
||||||
// The main form:
|
|
||||||
serviceCollection.AddSingleton<Main>();
|
|
||||||
|
|
||||||
// The database:
|
// The database:
|
||||||
serviceCollection.AddDatabase(loader.DataFile, true);
|
serviceCollection.AddDatabase(loader.DataFile, true);
|
||||||
});
|
});
|
||||||
@ -50,15 +48,15 @@ internal static class Program
|
|||||||
// Get a service provider:
|
// Get a service provider:
|
||||||
SERVICE_PROVIDER = scope.ServiceProvider;
|
SERVICE_PROVIDER = scope.ServiceProvider;
|
||||||
|
|
||||||
|
// Set the service provider to the processor:
|
||||||
|
ProcessorMeta.ServiceProvider = SERVICE_PROVIDER;
|
||||||
|
|
||||||
// Apply database migrations:
|
// Apply database migrations:
|
||||||
using (var database = SERVICE_PROVIDER.GetRequiredService<DataContext>())
|
using (var database = SERVICE_PROVIDER.GetRequiredService<DataContext>())
|
||||||
Setup.PerformDataMigration(database).Wait();
|
Setup.PerformDataMigration(database).Wait();
|
||||||
|
|
||||||
// Create the main window:
|
|
||||||
var mainWindow = SERVICE_PROVIDER.GetService<Main>();
|
|
||||||
|
|
||||||
// Start the app:
|
// Start the app:
|
||||||
Application.Run(mainWindow);
|
Application.Run(new Main());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user