Added the section user control

This commit is contained in:
Thorsten Sommer 2022-07-09 15:06:49 +02:00
parent 715159a6d9
commit 4ef0d91510
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
3 changed files with 329 additions and 0 deletions

View File

@ -0,0 +1,129 @@
namespace UI_WinForms.Components
{
partial class SectionTree
{
/// <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 Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.tableLayout = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutBottom = new System.Windows.Forms.FlowLayoutPanel();
this.buttonAdd = new System.Windows.Forms.Button();
this.buttonRemove = new System.Windows.Forms.Button();
this.treeView = new System.Windows.Forms.TreeView();
this.tableLayout.SuspendLayout();
this.flowLayoutBottom.SuspendLayout();
this.SuspendLayout();
//
// tableLayout
//
this.tableLayout.ColumnCount = 1;
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayout.Controls.Add(this.flowLayoutBottom, 0, 1);
this.tableLayout.Controls.Add(this.treeView, 0, 0);
this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayout.Location = new System.Drawing.Point(0, 0);
this.tableLayout.Name = "tableLayout";
this.tableLayout.RowCount = 2;
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 66F));
this.tableLayout.Size = new System.Drawing.Size(296, 511);
this.tableLayout.TabIndex = 0;
//
// flowLayoutBottom
//
this.flowLayoutBottom.Controls.Add(this.buttonAdd);
this.flowLayoutBottom.Controls.Add(this.buttonRemove);
this.flowLayoutBottom.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutBottom.Location = new System.Drawing.Point(0, 445);
this.flowLayoutBottom.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutBottom.Name = "flowLayoutBottom";
this.flowLayoutBottom.Size = new System.Drawing.Size(296, 66);
this.flowLayoutBottom.TabIndex = 0;
//
// buttonAdd
//
this.buttonAdd.AutoSize = true;
this.buttonAdd.Image = global::UI_WinForms.Resources.Icons.icons8_add_folder_512;
this.buttonAdd.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.buttonAdd.Location = new System.Drawing.Point(3, 3);
this.buttonAdd.Name = "buttonAdd";
this.buttonAdd.Size = new System.Drawing.Size(138, 60);
this.buttonAdd.TabIndex = 0;
this.buttonAdd.Text = "Add";
this.buttonAdd.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.buttonAdd.UseVisualStyleBackColor = true;
this.buttonAdd.Click += new System.EventHandler(this.buttonAdd_Click);
//
// buttonRemove
//
this.buttonRemove.AutoSize = true;
this.buttonRemove.Enabled = false;
this.buttonRemove.Image = global::UI_WinForms.Resources.Icons.icons8_delete_folder_512;
this.buttonRemove.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.buttonRemove.Location = new System.Drawing.Point(147, 3);
this.buttonRemove.Name = "buttonRemove";
this.buttonRemove.Size = new System.Drawing.Size(138, 60);
this.buttonRemove.TabIndex = 1;
this.buttonRemove.Text = "Remove";
this.buttonRemove.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.buttonRemove.UseVisualStyleBackColor = true;
//
// treeView
//
this.treeView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.treeView.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeView.HideSelection = false;
this.treeView.ItemHeight = 50;
this.treeView.Location = new System.Drawing.Point(3, 3);
this.treeView.Name = "treeView";
this.treeView.Size = new System.Drawing.Size(290, 439);
this.treeView.TabIndex = 1;
//
// SectionTree
//
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.Controls.Add(this.tableLayout);
this.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.Name = "SectionTree";
this.Size = new System.Drawing.Size(296, 511);
this.tableLayout.ResumeLayout(false);
this.flowLayoutBottom.ResumeLayout(false);
this.flowLayoutBottom.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private TableLayoutPanel tableLayout;
private FlowLayoutPanel flowLayoutBottom;
private Button buttonAdd;
private Button buttonRemove;
private TreeView treeView;
}
}

View File

@ -0,0 +1,140 @@
using DataModel.Database;
using DataModel.Database.Common;
using Microsoft.Extensions.DependencyInjection;
using Processor;
using UI_WinForms.Dialogs;
using UI_WinForms.Resources;
namespace UI_WinForms.Components;
public partial class SectionTree : UserControl
{
private readonly DataContext db;
public SectionTree()
{
this.InitializeComponent();
// 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:
var imgList = new ImageList();
imgList.ImageSize = new Size(45, 45);
imgList.ColorDepth = ColorDepth.Depth32Bit;
imgList.Images.Add(Icons.icons8_documents_folder_512);
// Set the image list to the tree view:
this.treeView.ImageList = imgList;
// Subscribe to the load event:
this.Load += this.OnLoad;
}
private async void OnLoad(object? sender, EventArgs e)
{
// A dictionary to cache all known tree nodes:
var treeNodes = new Dictionary<string, TreeNode>();
// Get the max. depth of the tree:
var maxDepth = await SectionProcessor.GetDepth(this.db);
// Store nodes, where we cannot find the parents:
var missingParents = new List<TreeNode>();
// Populate the tree view out of the database, layer by layer:
for (var i = 0; i <= maxDepth; i++)
{
await foreach (var section in SectionProcessor.LoadLayer(this.db, i))
{
// Create the tree node:
var node = new TreeNode
{
Name = section.DataKey, // [sic] name is the key
Text = section.Name,
StateImageIndex = 1,
};
// Cache the node:
treeNodes.Add(section.DataKey, node);
// Is this a root node?
if (section.Depth is 0)
// Set the root node:
this.treeView.Nodes.Add(node);
// Otherwise, attach this section to its parent node:
else
{
// Get the parent from our cache within O(1):
treeNodes.TryGetValue(section.Parent?.DataKey ?? string.Empty, out var parent);
// If the parent node is not found, skip this section:
if (parent is null)
{
missingParents.Add(node);
continue;
}
// Add the node to the parent:
parent.Nodes.Add(node);
}
}
}
// If we found any missing parents, show a dialog:
if (missingParents.Any())
{
MessageBox.Show($"In {missingParents.Count} case(s) we could not found the matching parent. We added these nodes to a special root node, though.", "Parent not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Create a root node for all missing parents:
var rootMissedParents = new TreeNode
{
Name = "MISSING_PARENTS",
Text = "Missing Parents",
StateImageIndex = 1,
};
// Add the root node to the tree:
this.treeView.Nodes.Add(rootMissedParents);
// Add all missing parents to the root node:
foreach (var node in missingParents)
rootMissedParents.Nodes.Add(node);
}
}
private async void buttonAdd_Click(object sender, EventArgs e)
{
var result = InputDialog.Show("Please type the desired section name.", "Add a section", "My next section");
if(result.DialogResult == DialogResult.Cancel)
return;
// Get the currently selected section as parent:
var selectedNode = this.treeView.SelectedNode;
// Add the new section to the database:
var addedSection = await SectionProcessor.AddSection(this.db, result.Text, result.IsRoot ? null : selectedNode?.Name);
// Add the new section to the tree control:
var node = new TreeNode
{
Name = addedSection.DataKey, // [sic] name is the key
Text = addedSection.Name,
StateImageIndex = 1,
};
if(!result.IsRoot && selectedNode is not null)
selectedNode.Nodes.Add(node);
else
this.treeView.Nodes.Add(node);
// Ensure, that the added node is visible and gets the focus:
node.EnsureVisible();
this.treeView.SelectedNode = node;
}
}

View File

@ -0,0 +1,60 @@
<root>
<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>