Продолжение рефакторинга (вынесение 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,106 @@
<UserControl
x:Class="Pf2e.WPF.EntityViewer.Component.EntityListControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodel="clr-namespace:Pf2e.WPF.EntityViewer.ViewModel"
Padding="3,3,3,3"
d:DataContext="{d:DesignInstance Type=viewmodel:EntityListViewModel}"
d:DesignHeight="450"
d:DesignWidth="400"
x:ClassModifier="internal"
mc:Ignorable="d">
<UserControl.Background>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ControlColorKey}}" />
</UserControl.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Grid.Column="0">
<Button
Width="25"
Margin="0,0,3,0"
Command="{Binding FirstPageCommand}"
Content="&lt;&lt;"
DockPanel.Dock="Left"
IsEnabled="{Binding HasPrevious}" />
<Button
Width="25"
Margin="0,0,3,0"
Command="{Binding PreviousPageCommand}"
Content="&lt;"
DockPanel.Dock="Left"
IsEnabled="{Binding HasPrevious}" />
<Button
Width="25"
Margin="3,0,0,0"
Command="{Binding LastPageCommand}"
Content="&gt;&gt;"
DockPanel.Dock="Right"
IsEnabled="{Binding HasNext}" />
<Button
Width="25"
Margin="3,0,0,0"
Command="{Binding NextPageCommand}"
Content="&gt;"
DockPanel.Dock="Right"
IsEnabled="{Binding HasNext}" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Label VerticalContentAlignment="Center" Content="Страница" />
<TextBox
Width="30"
VerticalContentAlignment="Center"
PreviewTextInput="TextBox_PreviewTextInput">
<TextBox.Text>
<Binding
Mode="TwoWay"
Path="Page"
UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>
<Label VerticalContentAlignment="Center" Content="из" />
<Label VerticalContentAlignment="Center" Content="{Binding PageCount, Mode=OneWay}" />
</StackPanel>
</DockPanel>
<TextBox
Grid.Row="1"
Margin="0,3,0,3"
VerticalAlignment="Center"
Text="TextBox"
TextWrapping="Wrap" />
<ListView
Grid.Row="2"
d:ItemsSource="{d:SampleData ItemCount=50}"
ItemsSource="{Binding Entities}"
SelectedItem="{Binding SelectedEntity}">
<ListView.View>
<GridView>
<GridViewColumn
Width="Auto"
DisplayMemberBinding="{Binding Id}"
Header="ID" />
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Название" />
<GridViewColumn
Width="Auto"
DisplayMemberBinding="{Binding Rarity}"
Header="Редк." />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
@@ -0,0 +1,20 @@
namespace Pf2e.WPF.EntityViewer.Component;
/// <summary>
/// Логика взаимодействия для DbEntityListControl.xaml
/// </summary>
internal partial class EntityListControl : System.Windows.Controls.UserControl
{
public EntityListControl()
{
InitializeComponent();
}
private void TextBox_PreviewTextInput(
object sender,
System.Windows.Input.TextCompositionEventArgs e
)
{
e.Handled = !int.TryParse(e.Text, out int result);
}
}
@@ -0,0 +1,171 @@
<UserControl
x:Class="Pf2e.WPF.EntityViewer.Component.ViewControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:component="clr-namespace:Pf2e.WPF.EntityViewer.Component"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.awesome.incremented/wpf/xaml/fontawesome.sharp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:struct="clr-namespace:Pf2e.WPF.EntityViewer.EntityViewStructure"
xmlns:viewmodel="clr-namespace:Pf2e.WPF.EntityViewer.ViewModel"
x:Name="_this"
d:DataContext="{d:DesignInstance Type=viewmodel:ViewViewModel}"
d:DesignHeight="450"
d:DesignWidth="300"
x:ClassModifier="internal"
mc:Ignorable="d">
<UserControl.Resources>
<FontFamily x:Key="FontAwesome">/FontAwesome.Sharp;component/fonts/#Font Awesome 6 Free Solid</FontFamily>
<struct:ColorAdapterConverter x:Key="ColorAdapterConverter" />
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="{Binding ButtonSize, ElementName=_this}" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Width" Value="{Binding ButtonSize, ElementName=_this}" />
<Setter Property="Height" Value="{Binding ButtonSize, ElementName=_this}" />
<Setter Property="BorderThickness" Value="2,2,1,1" />
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ControlColorKey}}" />
</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ControlColorKey}}" />
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="DarkSlateGray" />
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent" />
</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>
<SolidColorBrush Color="Transparent" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style
x:Key="FaButtonStyle"
BasedOn="{StaticResource ButtonStyle}"
TargetType="Button">
<Setter Property="FontFamily" Value="{StaticResource FontAwesome}" />
</Style>
<Style x:Key="HoverRow" TargetType="Grid">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrush}}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<UserControl.BorderBrush>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ActiveBorderColorKey}}" />
</UserControl.BorderBrush>
<UserControl.Background>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ControlColorKey}}" />
</UserControl.Background>
<ScrollViewer>
<ItemsControl AlternationCount="2" ItemsSource="{Binding Rows}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Grid.IsSharedSizeScope="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid
x:Name="FooBar"
Height="{Binding ItemHeight, ElementName=_this}"
Visibility="{Binding ItemVisibility}">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="ColumnOne" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<component:ViewLadder
Width="65"
Height="{Binding ItemHeight, ElementName=_this}"
DepthSize="{Binding DepthSize, ElementName=_this}"
Ladder="{Binding Ladder}" />
<Button
Margin="-20,0,0,0"
Padding="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding CollapseCommand}"
Style="{StaticResource FaButtonStyle}"
Visibility="{Binding ButtonVisibility}">
<TextBlock Margin="-3,-3,0,0" Text="{Binding ButtonIcon}" />
</Button>
<TextBlock
Margin="2,0,10,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding Name}" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock
Margin="0,0,5,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="{Binding TypeFontSize, ElementName=_this}"
FontStyle="Italic"
Text="{Binding Type}">
<TextBlock.Foreground>
<MultiBinding Converter="{StaticResource ColorAdapterConverter}">
<Binding Path="AccentColor" />
</MultiBinding>
</TextBlock.Foreground>
</TextBlock>
<TextBox
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Transparent"
BorderThickness="0"
IsReadOnly="True"
Text="{Binding Value, Mode=OneWay}">
<TextBox.Foreground>
<MultiBinding Converter="{StaticResource ColorAdapterConverter}">
<Binding Path="AccentColor" />
</MultiBinding>
</TextBox.Foreground>
</TextBox>
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter TargetName="FooBar" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrush}}" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter TargetName="FooBar" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrush}}" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Pf2e.Scrapper.Helpers;
namespace Pf2e.WPF.EntityViewer.Component;
internal partial class ViewControl : UserControl
{
#region "Поля элемента управления"
/// <summary>
/// Высота строки поля структуры.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The height of each item in the tree view.")]
public double ItemHeight
{
get { return (double)GetValue(ItemHeightProperty); }
set { SetValue(ItemHeightProperty, value); }
}
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
"ItemHeight",
typeof(double),
typeof(ViewControl),
new PropertyMetadata(20.0)
);
/// <summary>
/// Ширина отступа глубины.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of tab.")]
public double DepthSize
{
get { return (double)GetValue(DepthSizeProperty); }
set { SetValue(DepthSizeProperty, value); }
}
public static readonly DependencyProperty DepthSizeProperty = DependencyProperty.Register(
"DepthSize",
typeof(double),
typeof(ViewControl),
new PropertyMetadata(20.0)
);
/// <summary>
/// Размер шрифта типа поля сущности.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of tab.")]
public double TypeFontSize
{
get { return (double)GetValue(TypeFontSizeProperty); }
set { SetValue(TypeFontSizeProperty, value); }
}
public static readonly DependencyProperty TypeFontSizeProperty = DependencyProperty.Register(
"TypeFontSize",
typeof(double),
typeof(ViewControl),
new PropertyMetadata(9.5)
);
/// <summary>
/// Размер кнопки плюс/минус.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of plus/minus button.")]
public double ButtonSize
{
get { return (double)GetValue(ButtonSizeProperty); }
set { SetValue(ButtonSizeProperty, value); }
}
public static readonly DependencyProperty ButtonSizeProperty = DependencyProperty.Register(
"ButtonSize",
typeof(double),
typeof(ViewControl),
new PropertyMetadata(12.0)
);
#endregion
public ViewControl()
{
InitializeComponent();
}
}
@@ -0,0 +1,13 @@
<UserControl
x:Class="Pf2e.WPF.EntityViewer.Component.ViewLadder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Pf2e.WPF.EntityViewer.Component"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="20"
d:DesignWidth="60"
x:ClassModifier="internal"
mc:Ignorable="d">
<Canvas x:Name="TargetCanvas" />
</UserControl>
@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Pf2e.WPF.EntityViewer;
using Pf2e.WPF.EntityViewer.EntityViewStructure;
namespace Pf2e.WPF.EntityViewer.Component;
/// <summary>
/// Логика взаимодействия для ViewLadder.xaml
/// </summary>
internal partial class ViewLadder : UserControl
{
/// <summary>
/// Ширина отступа глубины.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of tab.")]
public double DepthSize
{
get { return (double)GetValue(DepthSizeProperty); }
set { SetValue(DepthSizeProperty, value); }
}
public static readonly DependencyProperty DepthSizeProperty = DependencyProperty.Register(
"DepthSize",
typeof(double),
typeof(ViewLadder),
new FrameworkPropertyMetadata(20.0, new PropertyChangedCallback(OnValueChanged))
);
public IEnumerable<LadderType> Ladder
{
get { return (IEnumerable<LadderType>)GetValue(LadderProperty); }
set { SetValue(LadderProperty, value); }
}
public static readonly DependencyProperty LadderProperty = DependencyProperty.Register(
"Ladder",
typeof(IEnumerable<LadderType>),
typeof(ViewLadder),
new FrameworkPropertyMetadata(
Array.Empty<LadderType>(),
new PropertyChangedCallback(OnValueChanged)
)
);
private static void OnValueChanged(
DependencyObject obj,
DependencyPropertyChangedEventArgs args
)
{
ViewLadder control = (ViewLadder)obj;
control.Rebuild();
}
public ViewLadder()
{
InitializeComponent();
}
public void Rebuild()
{
int n = Ladder.Count();
Width = n * DepthSize;
DrawingGroup result = new();
result.Children.Add(
new GeometryDrawing()
{
Geometry = new RectangleGeometry(new(0, 0, n * DepthSize, Height)),
Pen = new(Brushes.Transparent, 0),
}
);
result.Children.Add(
new GeometryDrawing()
{
Geometry = GetLadderGeometryGroup(Ladder, DepthSize, Height),
Pen = new(Brushes.Black, 1),
}
);
TargetCanvas.Background = new DrawingBrush(result);
}
private GeometryGroup GetLadderGeometryGroup(IEnumerable<LadderType> ladder, double w, double h)
{
GeometryGroup geometryGroup = new();
double w2 = w / 2;
double h2 = h / 2;
int i = 0;
foreach (LadderType ladderType in ladder)
{
switch (ladderType)
{
case LadderType.Empty:
break;
case LadderType.Last:
geometryGroup.Children.Add(
new LineGeometry(new(i * w + w2, 0), new(i * w + w2, h2))
);
geometryGroup.Children.Add(
new LineGeometry(new(i * w + w2, h2), new(i * w + w, h2))
);
break;
case LadderType.Through:
geometryGroup.Children.Add(
new LineGeometry(new(i * w + w2, 0), new(i * w + w2, h))
);
if (i == ladder.Count() - 1)
{
geometryGroup.Children.Add(
new LineGeometry(new(i * w + w2, h2), new(i * w + w, h2))
);
}
break;
default:
throw new ArgumentOutOfRangeException(nameof(ladder));
}
i++;
}
return geometryGroup;
}
}