Продолжение рефакторинга (вынесение WPF в отдельный проект)

This commit is contained in:
2025-10-02 17:25:48 +04:00
parent 2fa94851cb
commit f5b311e025
161 changed files with 899 additions and 559 deletions
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Pf2e.Database;
using Pf2e.Database.Model.Base;
using Pf2e.Database.Model.Enum;
using Pf2e.Scrapper.WPF.EntityViewer.Stores;
namespace Pf2e.WPF.EntityViewer.ViewModel;
internal class EntityFormViewModel : ViewModelBase
{
#region "Конструктор"
public IServiceProvider ServiceProvider { get; }
public Pf2eDbContext Context { get; }
public EntityListViewModel DbEntityListViewModel { get; }
public ViewViewModel ViewViewModel { get; }
public SelectedEntityTypeStore SelectedEntityTypeStore { get; }
public SelectedEntityStore SelectedEntityStore { get; }
public EntityFormViewModel(
IServiceProvider serviceProvider,
Pf2eDbContext context,
EntityListViewModel entityListViewModel,
ViewViewModel viewViewModel,
SelectedEntityTypeStore selectedEntityTypeStore,
SelectedEntityStore selectedEntityStore
)
{
ServiceProvider = serviceProvider;
Context = context;
DbEntityListViewModel = entityListViewModel;
ViewViewModel = viewViewModel;
SelectedEntityTypeStore = selectedEntityTypeStore;
SelectedEntityStore = selectedEntityStore;
Update();
SelectedEntityStore.SelectedEntityChanged += SelectedEntityStore_SelectedEntityChanged;
}
public void Update()
{
LoadEntityTypes();
}
#endregion
#region "Выбор типа"
public IEnumerable<EntityType> EntityTypes { get; set; } = [];
public EntityType? SelectedEntityType
{
get => SelectedEntityTypeStore.SelectedEntityType;
set
{
SelectedEntityTypeStore.SelectedEntityType = value;
OnPropertyChanged();
}
}
private void LoadEntityTypes()
{
EntityTypes = Context.Entities.Select(e => e.Type).Distinct().Order().ToList();
OnPropertyChanged(nameof(EntityTypes));
SelectedEntityTypeStore.SelectedEntityType = EntityTypes.Any() ? EntityTypes.First() : null;
}
#endregion
#region "Текущий элемент"
public string SelectedEntityDescription
{
get => SelectedEntityStore.SelectedEntity?.Description ?? "";
}
private void SelectedEntityStore_SelectedEntityChanged(Entity? obj)
{
OnPropertyChanged(nameof(SelectedEntityDescription));
}
#endregion
public string TestText => SelectedEntityType?.ToString() ?? "null";
}
@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Pf2e.Database;
using Pf2e.Database.Model.Base;
using Pf2e.Database.Model.Enum;
using Pf2e.Scrapper.WPF.EntityViewer.Stores;
namespace Pf2e.WPF.EntityViewer.ViewModel;
internal class EntityListViewModel : ViewModelBase
{
public Pf2eDbContext Context { get; }
public SelectedEntityTypeStore SelectedEntityTypeStore { get; }
public SelectedEntityStore SelectedEntityStore { get; }
private EntityType? SelectedEntityType => SelectedEntityTypeStore.SelectedEntityType;
public Entity? SelectedEntity
{
get => SelectedEntityStore.SelectedEntity;
set => SelectedEntityStore.SelectedEntity = value;
}
public int Page
{
get => _page;
set
{
_page = Math.Clamp(value, 1, PageCount);
OnPropertyChanged();
OnPropertyChanged(nameof(HasPrevious));
OnPropertyChanged(nameof(HasNext));
Reload();
}
}
private int _page = 1;
public int EntitiesCount
{
get => _entitiesCount;
set
{
_entitiesCount = value;
OnPropertyChanged();
OnPropertyChanged(nameof(PageCount));
OnPropertyChanged(nameof(HasPrevious));
OnPropertyChanged(nameof(HasNext));
}
}
private int _entitiesCount = 1;
public int PerPage
{
get => _perPage;
set
{
_perPage = value;
OnPropertyChanged();
OnPropertyChanged(nameof(PageCount));
Reload();
}
}
private int _perPage = 30;
public string Search
{
get => _search;
set
{
_search = value;
OnPropertyChanged();
Reload();
}
}
private string _search = "";
public int PageCount => Convert.ToInt32(Math.Ceiling(1.0 * EntitiesCount / PerPage));
public IEnumerable<Entity> Entities
{
get => _entities;
set
{
_entities = [.. value];
SelectedEntity = Entities.FirstOrDefault();
OnPropertyChanged();
}
}
private ObservableCollection<Entity> _entities = [];
public EntityListViewModel(
Pf2eDbContext context,
SelectedEntityTypeStore selectedEntityTypeStore,
SelectedEntityStore selectedEntityStore
)
{
Context = context;
SelectedEntityTypeStore = selectedEntityTypeStore;
SelectedEntityStore = selectedEntityStore;
SelectedEntityTypeStore.SelectedEntityTypeChanged +=
SelectedEntityTypeStore_SelectedEntityTypeChanged;
}
~EntityListViewModel()
{
SelectedEntityTypeStore.SelectedEntityTypeChanged -=
SelectedEntityTypeStore_SelectedEntityTypeChanged;
}
private void SelectedEntityTypeStore_SelectedEntityTypeChanged(EntityType? entityType)
{
if (entityType is null)
{
Page = 1;
EntitiesCount = 1;
Entities = [];
return;
}
Page = 1;
Reload();
}
#region "Методы кнопок"
private PageNavigationCommand? _firstPageCommand;
public PageNavigationCommand FirstPageCommand
{
get
{
return _firstPageCommand ??= new PageNavigationCommand(() =>
{
Page = 1;
});
}
}
private PageNavigationCommand? _previousPageCommand;
public PageNavigationCommand PreviousPageCommand
{
get
{
return _previousPageCommand ??= new PageNavigationCommand(() =>
{
Page--;
});
}
}
private PageNavigationCommand? _nextPageCommand;
public PageNavigationCommand NextPageCommand
{
get
{
return _nextPageCommand ??= new PageNavigationCommand(() =>
{
Page++;
});
}
}
private PageNavigationCommand? _lastPageCommand;
public PageNavigationCommand LastPageCommand
{
get
{
return _lastPageCommand ??= new PageNavigationCommand(() =>
{
Page = PageCount;
});
}
}
public bool HasPrevious => Page != 1;
public bool HasNext => Page != PageCount;
#endregion
#region "Запросы"
/// <summary>
/// Выполняет запрос к базе данных и обрабатывает результаты.
/// </summary>
public void Reload()
{
Pf2eDbContext dbContext = new();
IQueryable<Entity> query =
Search == ""
? dbContext.Entities.Where(e => e.Type == SelectedEntityType)
:
// ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall
dbContext.Entities.Where(e =>
e.Type == SelectedEntityType && Pf2eDbContext.LocaleSearch(e.Name, Search)
);
EntitiesCount = query.Count();
Entities = [.. query.OrderBy(e => e.Id).Skip((Page - 1) * PerPage).Take(PerPage).ToList()];
}
#endregion
}
/// <summary>
/// Команда для навигации по страницам.
/// </summary>
/// <param name="action">Действие, выполняемое при выполнении команды.</param>
public class PageNavigationCommand(Action action) : System.Windows.Input.ICommand
{
/// <summary>
/// Действие, выполняемое при выполнении команды.
/// </summary>
public Action Action { get; } = action;
/// <summary>
/// Событие, вызываемое при изменении возможности выполнения команды.
/// </summary>
public event EventHandler? CanExecuteChanged;
/// <summary>
/// Проверяет, может ли команда быть выполнена с указанным параметром.
/// </summary>
/// <param name="parameter">Параметр команды.</param>
/// <returns>Флаг, указывающий, может ли команда быть выполнена.</returns>
public bool CanExecute(object? parameter)
{
return true;
}
/// <summary>
/// Выполняет команду с указанным параметром.
/// </summary>
/// <param name="parameter">Параметр команды.</param>
public void Execute(object? parameter)
{
Action.Invoke();
}
}
@@ -0,0 +1,153 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Pf2e.Database;
using Pf2e.Scrapper.Helpers;
using Pf2e.Scrapper.WPF.EntityViewer.EntityViewStructure;
using Pf2e.Scrapper.WPF.EntityViewer.Stores;
namespace Pf2e.WPF.EntityViewer.ViewModel;
internal class ViewViewModel : ViewModelBase
{
public Pf2eDbContext Context { get; }
public SelectedEntityStore SelectedEntityStore { get; }
public FullEntity? CurrentEntityView
{
get => _currentEntityView;
set
{
_currentEntityView = value;
OnPropertyChanged();
}
}
private FullEntity? _currentEntityView;
public ObservableCollection<StructureRow> Rows
{
get => _rows;
set
{
_rows = value;
OnPropertyChanged();
}
}
private ObservableCollection<StructureRow> _rows = [];
private readonly List<StructureField> _fields = [];
private readonly List<StructureRow> _allRows = [];
public ViewViewModel(Pf2eDbContext context, SelectedEntityStore selectedEntityStore)
{
Context = context;
SelectedEntityStore = selectedEntityStore;
SelectedEntityStore.SelectedEntityChanged += SelectedEntityStore_SelectedEntityTypeChanged;
}
~ViewViewModel()
{
SelectedEntityStore.SelectedEntityChanged -= SelectedEntityStore_SelectedEntityTypeChanged;
}
private void SelectedEntityStore_SelectedEntityTypeChanged(Database.Model.Base.Entity? entity)
{
if (entity is null)
{
CurrentEntityView = null;
return;
}
CurrentEntityView = new(Context, entity.Type, entity.Id);
if (CurrentEntityView.Entity is null)
{
CurrentEntityView = null;
return;
}
StructureBuilder builder = new();
_fields.Clear();
_fields.Add(builder.Create("Entity", CurrentEntityView.Entity));
if (CurrentEntityView.SubEntity is not null)
{
string typeName = CurrentEntityView.SubEntity.GetType().Name;
_fields.Add(builder.Create(typeName, CurrentEntityView.SubEntity));
}
_allRows.Clear();
_allRows.AddRange(
_fields.SelectMany(field =>
field.GetRows(structureField => new StructureRow(structureField))
)
);
Rows.Clear();
foreach (StructureRow row in _allRows)
{
Rows.Add(row);
row.OnChange += Row_OnChange;
}
BuildLadder();
OnPropertyChanged(nameof(Rows));
}
private void Row_OnChange(StructureRow row, StructureField field)
{
OnPropertyChanged(nameof(Rows));
}
/// <summary>
/// Построение лестницы для строк полей структуры.
/// </summary>
private void BuildLadder()
{
List<LadderType> lastLadder = [];
for (int i = Rows.Count - 1; i >= 0; i--)
{
StructureRow row = Rows[i];
List<LadderType> ladder;
if (row.Depth == 0)
{
ladder = [];
}
else if (row.Depth < lastLadder.Count)
{
ladder =
[
.. lastLadder[..(row.Depth - 1)],
lastLadder[row.Depth - 1] == LadderType.Empty
? LadderType.Last
: LadderType.Through,
];
}
else if (row.Depth == lastLadder.Count)
{
ladder = lastLadder;
}
else
{
ladder =
[
.. lastLadder,
.. Enumerable.Repeat(LadderType.Empty, row.Depth - lastLadder.Count - 1),
LadderType.Last,
];
}
row.Ladder = ladder;
lastLadder = ladder.Select(l => l == LadderType.Last ? LadderType.Through : l).ToList();
}
}
}