Пагинация запросов и исправление отображений

This commit is contained in:
2025-04-18 22:47:25 +04:00
parent 29aee61d4c
commit db432929bf
3 changed files with 249 additions and 38 deletions
+42 -22
View File
@@ -4,7 +4,9 @@ using Newtonsoft.Json.Linq;
using Pf2eModel;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Base.Source;
using Pf2eModel.Model.Structure;
using System.ComponentModel;
namespace Pf2eViewer;
internal class EntityConverter : JsonConverter
@@ -16,44 +18,62 @@ internal class EntityConverter : JsonConverter
return objectType == typeof(Entity) || objectType.IsAssignableTo(typeof(IEntity));
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
private Dictionary<string, object?> DictionarySerialization(object source)
{
JToken token = JToken.FromObject(value!);
Dictionary<string, object?> dictionary = [];
if (token.Type != JTokenType.Object)
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
{
token.WriteTo(writer);
return;
object? v = property.GetValue(source);
dictionary.Add(property.Name, v);
}
JObject obj = (JObject) token;
return dictionary;
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
Dictionary<string, object?> dictionary = DictionarySerialization(value!);
if (value.GetType() != typeof(Entity))
{
dictionary.Remove("Entity");
}
switch (value)
{
case Entity e:
obj = ProcessEntity(obj, e);
case Entity entity:
ProcessEntity(dictionary, entity);
break;
case Trait trait:
ProcessTrait(dictionary, trait);
break;
}
obj.WriteTo(writer);
writer.WriteStartObject();
foreach (KeyValuePair<string, object> keyValuePair in dictionary)
{
writer.WritePropertyName(keyValuePair.Key, true);
serializer.Serialize(writer, keyValuePair.Value);
}
private JObject ProcessEntity(JObject obj, Entity e)
{
List<int> traitIds = e.Traits.Select(t => t.Id).ToList();
List<Trait> traits = _context.Traits.Where(t => traitIds.Contains(t.Id)).Include(t => t.Entity).ToList();
foreach (JToken item in (JArray) obj.SelectToken("Traits")!)
{
JObject o = (JObject) item;
int id = o.SelectToken("Id")!.ToObject<int>();
o.Add("Name", traits.FirstOrDefault(t => t.Id == id)!.Entity.Name);
writer.WriteEndObject();
}
obj.Remove("Description");
private void ProcessTrait(Dictionary<string, object?> dictionary, Trait trait)
{
string name = trait.Entity?.Name ?? _context.Entities.Where(e => e.Id == trait.Id).Select(e => e.Name).FirstOrDefault()!;
return obj;
dictionary.Remove("Entity");
dictionary.Remove("Entities");
dictionary.Add("Name", name);
}
private void ProcessEntity(Dictionary<string, object?> dictionary, Entity entity)
{
dictionary.Remove("Description");
}
public override bool CanRead => false;
+107 -10
View File
@@ -32,6 +32,13 @@ partial class MainViewForm
InnerSplitContainer = new SplitContainer();
TypesListBox = new ListBox();
EntityGridView = new DataGridView();
PaginationPagel = new Panel();
PageTextBox = new TextBox();
PaginationLabel = new TextBox();
LastPageButton = new Button();
NextPageButton = new Button();
PrevPageButton = new Button();
FirstPageButton = new Button();
ResultSplitContainer = new SplitContainer();
EntityTreeView = new TreeView();
DescriptionTextBox = new TextBox();
@@ -44,6 +51,7 @@ partial class MainViewForm
InnerSplitContainer.Panel2.SuspendLayout();
InnerSplitContainer.SuspendLayout();
((System.ComponentModel.ISupportInitialize) EntityGridView).BeginInit();
PaginationPagel.SuspendLayout();
((System.ComponentModel.ISupportInitialize) ResultSplitContainer).BeginInit();
ResultSplitContainer.Panel1.SuspendLayout();
ResultSplitContainer.Panel2.SuspendLayout();
@@ -66,7 +74,7 @@ partial class MainViewForm
RootSplitContainer.Panel2.Controls.Add(ResultSplitContainer);
RootSplitContainer.Panel2MinSize = 400;
RootSplitContainer.Size = new Size(1181, 688);
RootSplitContainer.SplitterDistance = 200;
RootSplitContainer.SplitterDistance = 254;
RootSplitContainer.TabIndex = 0;
//
// InnerSplitContainer
@@ -83,8 +91,9 @@ partial class MainViewForm
// InnerSplitContainer.Panel2
//
InnerSplitContainer.Panel2.Controls.Add(EntityGridView);
InnerSplitContainer.Size = new Size(200, 688);
InnerSplitContainer.SplitterDistance = 274;
InnerSplitContainer.Panel2.Controls.Add(PaginationPagel);
InnerSplitContainer.Size = new Size(254, 688);
InnerSplitContainer.SplitterDistance = 102;
InnerSplitContainer.TabIndex = 1;
//
// TypesListBox
@@ -94,7 +103,7 @@ partial class MainViewForm
TypesListBox.ItemHeight = 15;
TypesListBox.Location = new Point(0, 0);
TypesListBox.Name = "TypesListBox";
TypesListBox.Size = new Size(200, 274);
TypesListBox.Size = new Size(254, 102);
TypesListBox.TabIndex = 0;
TypesListBox.SelectedIndexChanged += TypesListBox_SelectedIndexChanged;
//
@@ -105,17 +114,96 @@ partial class MainViewForm
EntityGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
EntityGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
EntityGridView.Dock = DockStyle.Fill;
EntityGridView.Location = new Point(0, 0);
EntityGridView.Location = new Point(0, 53);
EntityGridView.MultiSelect = false;
EntityGridView.Name = "EntityGridView";
EntityGridView.ReadOnly = true;
EntityGridView.RowHeadersVisible = false;
EntityGridView.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders;
EntityGridView.ShowEditingIcon = false;
EntityGridView.Size = new Size(200, 410);
EntityGridView.Size = new Size(254, 529);
EntityGridView.TabIndex = 0;
EntityGridView.RowStateChanged += EntityGridView_RowStateChanged;
//
// PaginationPagel
//
PaginationPagel.Controls.Add(PageTextBox);
PaginationPagel.Controls.Add(PaginationLabel);
PaginationPagel.Controls.Add(LastPageButton);
PaginationPagel.Controls.Add(NextPageButton);
PaginationPagel.Controls.Add(PrevPageButton);
PaginationPagel.Controls.Add(FirstPageButton);
PaginationPagel.Dock = DockStyle.Top;
PaginationPagel.Location = new Point(0, 0);
PaginationPagel.Name = "PaginationPagel";
PaginationPagel.Size = new Size(254, 53);
PaginationPagel.TabIndex = 1;
//
// PageTextBox
//
PageTextBox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
PageTextBox.Location = new Point(81, 4);
PageTextBox.Name = "PageTextBox";
PageTextBox.Size = new Size(92, 23);
PageTextBox.TabIndex = 8;
PageTextBox.Text = "1";
PageTextBox.TextAlign = HorizontalAlignment.Center;
PageTextBox.KeyPress += PageTextBox_KeyPress;
//
// PaginationLabel
//
PaginationLabel.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
PaginationLabel.BorderStyle = BorderStyle.None;
PaginationLabel.Location = new Point(3, 31);
PaginationLabel.Name = "PaginationLabel";
PaginationLabel.ReadOnly = true;
PaginationLabel.Size = new Size(248, 16);
PaginationLabel.TabIndex = 7;
PaginationLabel.Text = "Всего";
PaginationLabel.TextAlign = HorizontalAlignment.Center;
//
// LastPageButton
//
LastPageButton.Anchor = AnchorStyles.Top | AnchorStyles.Right;
LastPageButton.Location = new Point(218, 3);
LastPageButton.Name = "LastPageButton";
LastPageButton.Size = new Size(33, 23);
LastPageButton.TabIndex = 3;
LastPageButton.Text = ">>";
LastPageButton.UseVisualStyleBackColor = true;
LastPageButton.Click += LastPageButton_Click;
//
// NextPageButton
//
NextPageButton.Anchor = AnchorStyles.Top | AnchorStyles.Right;
NextPageButton.Location = new Point(179, 3);
NextPageButton.Name = "NextPageButton";
NextPageButton.Size = new Size(33, 23);
NextPageButton.TabIndex = 2;
NextPageButton.Text = ">";
NextPageButton.UseVisualStyleBackColor = true;
NextPageButton.Click += NextPageButton_Click;
//
// PrevPageButton
//
PrevPageButton.Location = new Point(42, 3);
PrevPageButton.Name = "PrevPageButton";
PrevPageButton.Size = new Size(33, 23);
PrevPageButton.TabIndex = 1;
PrevPageButton.Text = "<";
PrevPageButton.UseVisualStyleBackColor = true;
PrevPageButton.Click += PrevPageButton_Click;
//
// FirstPageButton
//
FirstPageButton.Location = new Point(3, 3);
FirstPageButton.Name = "FirstPageButton";
FirstPageButton.Size = new Size(33, 23);
FirstPageButton.TabIndex = 0;
FirstPageButton.Text = "<<";
FirstPageButton.UseVisualStyleBackColor = true;
FirstPageButton.Click += FirstPageButton_Click;
//
// ResultSplitContainer
//
ResultSplitContainer.Dock = DockStyle.Fill;
@@ -129,8 +217,8 @@ partial class MainViewForm
// ResultSplitContainer.Panel2
//
ResultSplitContainer.Panel2.Controls.Add(DescriptionTextBox);
ResultSplitContainer.Size = new Size(977, 688);
ResultSplitContainer.SplitterDistance = 495;
ResultSplitContainer.Size = new Size(923, 688);
ResultSplitContainer.SplitterDistance = 467;
ResultSplitContainer.TabIndex = 1;
//
// EntityTreeView
@@ -138,7 +226,7 @@ partial class MainViewForm
EntityTreeView.Dock = DockStyle.Fill;
EntityTreeView.Location = new Point(0, 0);
EntityTreeView.Name = "EntityTreeView";
EntityTreeView.Size = new Size(495, 688);
EntityTreeView.Size = new Size(467, 688);
EntityTreeView.TabIndex = 0;
//
// DescriptionTextBox
@@ -149,7 +237,7 @@ partial class MainViewForm
DescriptionTextBox.Name = "DescriptionTextBox";
DescriptionTextBox.ReadOnly = true;
DescriptionTextBox.ScrollBars = ScrollBars.Vertical;
DescriptionTextBox.Size = new Size(478, 688);
DescriptionTextBox.Size = new Size(452, 688);
DescriptionTextBox.TabIndex = 0;
//
// MainViewForm
@@ -169,6 +257,8 @@ partial class MainViewForm
((System.ComponentModel.ISupportInitialize) InnerSplitContainer).EndInit();
InnerSplitContainer.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize) EntityGridView).EndInit();
PaginationPagel.ResumeLayout(false);
PaginationPagel.PerformLayout();
ResultSplitContainer.Panel1.ResumeLayout(false);
ResultSplitContainer.Panel2.ResumeLayout(false);
ResultSplitContainer.Panel2.PerformLayout();
@@ -186,4 +276,11 @@ partial class MainViewForm
private TreeView EntityTreeView;
private SplitContainer ResultSplitContainer;
private TextBox DescriptionTextBox;
private Panel PaginationPagel;
private Button LastPageButton;
private Button NextPageButton;
private Button PrevPageButton;
private Button FirstPageButton;
private TextBox PageTextBox;
private TextBox PaginationLabel;
}
+99 -5
View File
@@ -1,6 +1,8 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Pf2eModel;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
@@ -29,10 +31,32 @@ public partial class MainViewForm : Form
TypesListBox.SelectedIndex = 0;
}
private void TypesListBox_SelectedIndexChanged(object sender, EventArgs _)
public const int PerPage = 20;
public int Count;
public int Page
{
if (TypesListBox.SelectedItem is null)
get => Convert.ToInt32(PageTextBox.Text);
set
{
PageTextBox.Text = value.ToString();
UpdateTreeView();
}
}
public int MaxPage => Convert.ToInt32(Math.Ceiling(1.0 * Count / PerPage));
private void UpdateTreeView()
{
EntityType type = (EntityType) TypesListBox.SelectedItem!;
Count = Context.Entities.Count(e => e.Type == type);
if (Page < 1 || Page > MaxPage)
{
Page = Math.Min(MaxPage, Math.Max(1, Page));
return;
}
@@ -40,15 +64,71 @@ public partial class MainViewForm : Form
.Where(e => e.Type == (EntityType) TypesListBox.SelectedItem)
.OrderBy(e => e.Id)
.Include(e => e.Sources)
.ThenInclude(s => s.Source)
.Include(e => e.Aliases)
.Include(e => e.Keywords)
.Include(e => e.Externals)
.ThenInclude(x => x.Target)
.Include(e => e.Traits)
.ThenInclude(t => t.Entity)
.Select(e => new EntityGridRow(e))
.Skip((Page - 1) * PerPage)
.Take(PerPage)
.ToList();
EntityGridView.Rows[0].Selected = true;
PaginationLabel.Text = $"Всего: {Count} объектов, {MaxPage} страниц";
FirstPageButton.Enabled = Page > 1;
PrevPageButton.Enabled = Page > 1;
NextPageButton.Enabled = Page < MaxPage;
LastPageButton.Enabled = Page < MaxPage;
}
private void TypesListBox_SelectedIndexChanged(object sender, EventArgs _)
{
if (TypesListBox.SelectedItem is null)
{
return;
}
Page = 1;
}
private void FirstPageButton_Click(object sender, EventArgs e)
{
Page = 1;
}
private void PrevPageButton_Click(object sender, EventArgs e)
{
Page--;
}
private void NextPageButton_Click(object sender, EventArgs e)
{
Page++;
}
private void LastPageButton_Click(object sender, EventArgs e)
{
Page = MaxPage;
}
private void PageTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
if (e.KeyChar == (char) Keys.Return)
{
UpdateTreeView();
}
}
private void EntityGridView_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
{
int rowsCount = EntityGridView.SelectedRows.Count;
@@ -72,18 +152,31 @@ public partial class MainViewForm : Form
{
JsonSerializerSettings settings = new()
{
Converters = [new EntityConverter()]
Converters = [
new EntityConverter(),
new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() },
]
};
string result = JsonConvert.SerializeObject(entity, settings);
Type type = EntityOfTypeAttribute.Resolve(entity);
string subResult = JsonConvert.SerializeObject(Context.Find(type, entity.Id), settings);
string subResult = JsonConvert.SerializeObject(ResolveEntity(entity), settings);
return result[..^1] + $",\"SubEntity\":{subResult}}}";
}
public IEntity? ResolveEntity(Entity entity)
{
switch (entity.Type)
{
case EntityType.Ancestry:
return Context.Ancestries
.FirstOrDefault(e => e.Id == entity.Id);
}
return null;
}
public static void JsonToTreeview(TreeView treeView, string jsonString, string rootName)
{
@@ -92,11 +185,11 @@ public partial class MainViewForm : Form
: JObject.Parse(jsonString);
treeView.Nodes.Clear();
foreach (TreeNode node in Element2TreeNode(json, rootName).Nodes)
{
treeView.Nodes.Add(node);
}
treeView.ExpandAll();
}
private static TreeNode Element2TreeNode(object element, string text = "")
@@ -156,4 +249,5 @@ public partial class MainViewForm : Form
public Entity GetEntity() => _e;
}
}