From a5202782d8f751bc03d2a3e2442fa1f3da56e9fd Mon Sep 17 00:00:00 2001 From: karoterra Date: Fri, 14 Jan 2022 19:45:40 +0900 Subject: [PATCH 01/24] =?UTF-8?q?:sparkles:=20feat:=20WPF=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=82=B8=E3=82=A7=E3=82=AF=E3=83=88=E3=81=A8=E7=A9=BA?= =?UTF-8?q?=E3=81=AE=E3=83=A1=E3=82=A4=E3=83=B3=E3=82=A6=E3=82=A3=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=82=A6=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AupInfo.Wpf/App.xaml | 42 ++++++++++++++++++ AupInfo.Wpf/App.xaml.cs | 23 ++++++++++ AupInfo.Wpf/AssemblyInfo.cs | 10 +++++ AupInfo.Wpf/AupInfo.Wpf.csproj | 18 ++++++++ AupInfo.Wpf/DataContextDisposeAction.cs | 13 ++++++ AupInfo.Wpf/ViewModels/MainWindowViewModel.cs | 43 +++++++++++++++++++ AupInfo.Wpf/Views/MainWindow.xaml | 31 +++++++++++++ AupInfo.Wpf/Views/MainWindow.xaml.cs | 15 +++++++ AupInfo.sln | 30 +++++++++++++ 9 files changed, 225 insertions(+) create mode 100644 AupInfo.Wpf/App.xaml create mode 100644 AupInfo.Wpf/App.xaml.cs create mode 100644 AupInfo.Wpf/AssemblyInfo.cs create mode 100644 AupInfo.Wpf/AupInfo.Wpf.csproj create mode 100644 AupInfo.Wpf/DataContextDisposeAction.cs create mode 100644 AupInfo.Wpf/ViewModels/MainWindowViewModel.cs create mode 100644 AupInfo.Wpf/Views/MainWindow.xaml create mode 100644 AupInfo.Wpf/Views/MainWindow.xaml.cs create mode 100644 AupInfo.sln diff --git a/AupInfo.Wpf/App.xaml b/AupInfo.Wpf/App.xaml new file mode 100644 index 0000000..338fd10 --- /dev/null +++ b/AupInfo.Wpf/App.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AupInfo.Wpf/App.xaml.cs b/AupInfo.Wpf/App.xaml.cs new file mode 100644 index 0000000..15348ab --- /dev/null +++ b/AupInfo.Wpf/App.xaml.cs @@ -0,0 +1,23 @@ +using System.Text; +using System.Windows; +using Prism.Ioc; +using AupInfo.Wpf.Views; + +namespace AupInfo.Wpf +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App + { + protected override Window CreateShell() + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + return Container.Resolve(); + } + + protected override void RegisterTypes(IContainerRegistry containerRegistry) + { + } + } +} diff --git a/AupInfo.Wpf/AssemblyInfo.cs b/AupInfo.Wpf/AssemblyInfo.cs new file mode 100644 index 0000000..f60efc0 --- /dev/null +++ b/AupInfo.Wpf/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/AupInfo.Wpf/AupInfo.Wpf.csproj b/AupInfo.Wpf/AupInfo.Wpf.csproj new file mode 100644 index 0000000..9af3c32 --- /dev/null +++ b/AupInfo.Wpf/AupInfo.Wpf.csproj @@ -0,0 +1,18 @@ + + + + WinExe + net6.0-windows + enable + enable + true + + + + + + + + + + diff --git a/AupInfo.Wpf/DataContextDisposeAction.cs b/AupInfo.Wpf/DataContextDisposeAction.cs new file mode 100644 index 0000000..8506c97 --- /dev/null +++ b/AupInfo.Wpf/DataContextDisposeAction.cs @@ -0,0 +1,13 @@ +using System.Windows; +using Microsoft.Xaml.Behaviors; + +namespace AupInfo.Wpf +{ + internal class DataContextDisposeAction : TriggerAction + { + protected override void Invoke(object parameter) + { + (AssociatedObject?.DataContext as IDisposable)?.Dispose(); + } + } +} diff --git a/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs b/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..567e48c --- /dev/null +++ b/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,43 @@ +using System.Reactive.Disposables; +using Prism.Mvvm; +using Reactive.Bindings; +using Reactive.Bindings.Extensions; + +namespace AupInfo.Wpf.ViewModels +{ + public class MainWindowViewModel : BindableBase, IDisposable + { + private readonly CompositeDisposable disposables = new(); + + public ReactivePropertySlim Title { get; } + + public MainWindowViewModel() + { + Title = new ReactivePropertySlim("AupInfo").AddTo(disposables); + } + + #region IDisposable + + private bool disposedValue; + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + disposables.Dispose(); + } + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + #endregion + } +} diff --git a/AupInfo.Wpf/Views/MainWindow.xaml b/AupInfo.Wpf/Views/MainWindow.xaml new file mode 100644 index 0000000..bdb7fe6 --- /dev/null +++ b/AupInfo.Wpf/Views/MainWindow.xaml @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/AupInfo.Wpf/Views/MainWindow.xaml.cs b/AupInfo.Wpf/Views/MainWindow.xaml.cs new file mode 100644 index 0000000..74ace5e --- /dev/null +++ b/AupInfo.Wpf/Views/MainWindow.xaml.cs @@ -0,0 +1,15 @@ +using MahApps.Metro.Controls; + +namespace AupInfo.Wpf.Views +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : MetroWindow + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/AupInfo.sln b/AupInfo.sln new file mode 100644 index 0000000..7ce937c --- /dev/null +++ b/AupInfo.sln @@ -0,0 +1,30 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AupInfo.Wpf", "AupInfo.Wpf\AupInfo.Wpf.csproj", "{3BB2D48A-79FB-488E-AAD9-2AD71D716135}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9D95A2DE-2257-4732-9C93-0383719F0CAB}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3BB2D48A-79FB-488E-AAD9-2AD71D716135}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3BB2D48A-79FB-488E-AAD9-2AD71D716135}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3BB2D48A-79FB-488E-AAD9-2AD71D716135}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3BB2D48A-79FB-488E-AAD9-2AD71D716135}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4555072D-DD10-4187-89FB-ECEC371A0891} + EndGlobalSection +EndGlobal From 4d2aad5c67a7fc62f8f41803b8fc0b5642fc727b Mon Sep 17 00:00:00 2001 From: karoterra Date: Sat, 15 Jan 2022 17:23:08 +0900 Subject: [PATCH 02/24] =?UTF-8?q?:sparkles:=20feat:=20=E3=83=A2=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=A2=E3=83=83=E3=83=97=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AupInfo.Wpf/App.xaml.cs | 2 + AupInfo.Wpf/AupInfo.Wpf.csproj | 1 + .../ViewModels/EditHandlePanelViewModel.cs | 43 +++++++++ .../ViewModels/FilterProjectPanelViewModel.cs | 30 ++++++ AupInfo.Wpf/ViewModels/MainWindowViewModel.cs | 74 ++++++++++++++- AupInfo.Wpf/ViewModels/PanelItemViewModel.cs | 53 +++++++++++ AupInfo.Wpf/Views/EditHandlePanel.xaml | 52 +++++++++++ AupInfo.Wpf/Views/EditHandlePanel.xaml.cs | 15 +++ AupInfo.Wpf/Views/FilterProjectPanel.xaml | 15 +++ AupInfo.Wpf/Views/FilterProjectPanel.xaml.cs | 15 +++ AupInfo.Wpf/Views/MainWindow.xaml | 93 ++++++++++++++++++- 11 files changed, 388 insertions(+), 5 deletions(-) create mode 100644 AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs create mode 100644 AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs create mode 100644 AupInfo.Wpf/ViewModels/PanelItemViewModel.cs create mode 100644 AupInfo.Wpf/Views/EditHandlePanel.xaml create mode 100644 AupInfo.Wpf/Views/EditHandlePanel.xaml.cs create mode 100644 AupInfo.Wpf/Views/FilterProjectPanel.xaml create mode 100644 AupInfo.Wpf/Views/FilterProjectPanel.xaml.cs diff --git a/AupInfo.Wpf/App.xaml.cs b/AupInfo.Wpf/App.xaml.cs index 15348ab..337de36 100644 --- a/AupInfo.Wpf/App.xaml.cs +++ b/AupInfo.Wpf/App.xaml.cs @@ -18,6 +18,8 @@ protected override Window CreateShell() protected override void RegisterTypes(IContainerRegistry containerRegistry) { + containerRegistry.RegisterForNavigation(); + containerRegistry.RegisterForNavigation(); } } } diff --git a/AupInfo.Wpf/AupInfo.Wpf.csproj b/AupInfo.Wpf/AupInfo.Wpf.csproj index 9af3c32..4c3599d 100644 --- a/AupInfo.Wpf/AupInfo.Wpf.csproj +++ b/AupInfo.Wpf/AupInfo.Wpf.csproj @@ -13,6 +13,7 @@ + diff --git a/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs b/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs new file mode 100644 index 0000000..68a13ba --- /dev/null +++ b/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs @@ -0,0 +1,43 @@ +using System.Reactive.Disposables; +using Prism.Mvvm; +using Prism.Navigation; +using Reactive.Bindings; +using Reactive.Bindings.Extensions; + +namespace AupInfo.Wpf.ViewModels +{ + public class EditHandlePanelViewModel : BindableBase, IDestructible + { + public ReactivePropertySlim EditFilename { get; } + public ReactivePropertySlim OutputFilename { get; } + public ReactivePropertySlim ProjectFilename { get; } + public ReactivePropertySlim Width { get; } + public ReactivePropertySlim Height { get; } + public ReactivePropertySlim VideoRate { get; } + public ReactivePropertySlim AudioRate { get; } + public ReactivePropertySlim AudioCh { get; } + public ReactivePropertySlim FrameNum { get; } + public ReactivePropertySlim TimeLength { get; } + + private CompositeDisposable disposables = new(); + + public EditHandlePanelViewModel() + { + EditFilename = new ReactivePropertySlim("1920x1080_30fps_44100Hz.exedit").AddTo(disposables); + OutputFilename = new ReactivePropertySlim(@"C:\path\to\video.mp4").AddTo(disposables); + ProjectFilename = new ReactivePropertySlim(@"C:\path\to\project.aup").AddTo(disposables); + Width = new ReactivePropertySlim(1920).AddTo(disposables); + Height = new ReactivePropertySlim(1080).AddTo(disposables); + VideoRate = new ReactivePropertySlim("30").AddTo(disposables); + AudioRate = new ReactivePropertySlim(44100).AddTo(disposables); + AudioCh = new ReactivePropertySlim(2).AddTo(disposables); + FrameNum = new ReactivePropertySlim(120).AddTo(disposables); + TimeLength = new ReactivePropertySlim("00:00:00.000").AddTo(disposables); + } + + public void Destroy() + { + disposables.Dispose(); + } + } +} diff --git a/AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs b/AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs new file mode 100644 index 0000000..226ecc9 --- /dev/null +++ b/AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs @@ -0,0 +1,30 @@ +using System.Reactive.Disposables; +using Prism.Mvvm; +using Prism.Navigation; +using Reactive.Bindings; +using Reactive.Bindings.Extensions; + +namespace AupInfo.Wpf.ViewModels +{ + public class FilterProjectPanelViewModel : BindableBase, IDestructible + { + public ReactiveCollection Filters { get; } + + private CompositeDisposable disposables = new(); + + public FilterProjectPanelViewModel() + { + Filters = new ReactiveCollection().AddTo(disposables); + + Filters.Add("拡張編集"); + Filters.Add("ごちゃまぜドロップス"); + Filters.Add("PSDToolKit"); + Filters.Add("拡張編集RAMプレビュー"); + } + + public void Destroy() + { + disposables.Dispose(); + } + } +} diff --git a/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs b/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs index 567e48c..2487f0b 100644 --- a/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs +++ b/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs @@ -1,19 +1,83 @@ using System.Reactive.Disposables; +using System.Reactive.Linq; +using MaterialDesignThemes.Wpf; using Prism.Mvvm; +using Prism.Regions; using Reactive.Bindings; using Reactive.Bindings.Extensions; +using System.Windows.Input; namespace AupInfo.Wpf.ViewModels { public class MainWindowViewModel : BindableBase, IDisposable { - private readonly CompositeDisposable disposables = new(); - public ReactivePropertySlim Title { get; } + public ReactivePropertySlim Subtitle { get; } + + public ReactivePropertySlim IsMenuOpen { get; } + public ReactivePropertySlim IsModeless { get; } + public ReadOnlyReactivePropertySlim DrawerOpenMode { get; } + + public ReactiveCollection PanelItems { get; } + public ReactivePropertySlim SelectedIndex { get; } + public ReactivePropertySlim SelectedItem { get; } + + public ReactiveCommand Loaded { get; } + public ReactiveCommand SelectedItemClicked { get; } - public MainWindowViewModel() + private readonly CompositeDisposable disposables = new(); + private readonly IRegionManager regionManager; + + public MainWindowViewModel(IRegionManager regionManager) { + this.regionManager = regionManager; + Title = new ReactivePropertySlim("AupInfo").AddTo(disposables); + Subtitle = new ReactivePropertySlim("Title").AddTo(disposables); + IsMenuOpen = new ReactivePropertySlim(false).AddTo(disposables); + IsModeless = new ReactivePropertySlim(false).AddTo(disposables); + PanelItems = new ReactiveCollection().AddTo(disposables); + SelectedIndex = new ReactivePropertySlim(-1).AddTo(disposables); + SelectedItem = new ReactivePropertySlim(null).AddTo(disposables); + + DrawerOpenMode = IsModeless + .Select(x => x ? DrawerHostOpenMode.Standard : DrawerHostOpenMode.Modal) + .ToReadOnlyReactivePropertySlim() + .AddTo(disposables); + + Loaded = new ReactiveCommand() + .WithSubscribe(() => + { + SelectedIndex.Value = 0; + }) + .AddTo(disposables); + + SelectedItemClicked = new ReactiveCommand() + .WithSubscribe(e => + { + if (!IsModeless.Value) + IsMenuOpen.Value = false; + }) + .AddTo(disposables); + + SelectedItem.Subscribe(item => + { + if (!string.IsNullOrEmpty(item?.Navigation)) + { + this.regionManager.RequestNavigate("ContentRegion", item.Navigation); + Subtitle.Value = string.IsNullOrEmpty(item.Category) + ? item.Name + : $"{item.Category} - {item.Name}"; + if (!IsModeless.Value) + IsMenuOpen.Value = false; + } + }).AddTo(disposables); + + PanelItems.Add(new("エディットハンドル", "", "EditHandlePanel", SelectedItemClicked)); + PanelItems.Add(new("フィルタプラグイン", "", "FilterProjectPanel", SelectedItemClicked)); + PanelItems.Add(new("シーン", "拡張編集", "", SelectedItemClicked)); + PanelItems.Add(new("フォント", "拡張編集", "", SelectedItemClicked)); + PanelItems.Add(new("ファイル", "PSDToolKit", "", SelectedItemClicked)); } #region IDisposable @@ -26,6 +90,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { + foreach (var region in regionManager.Regions) + { + region.RemoveAll(); + } disposables.Dispose(); } disposedValue = true; diff --git a/AupInfo.Wpf/ViewModels/PanelItemViewModel.cs b/AupInfo.Wpf/ViewModels/PanelItemViewModel.cs new file mode 100644 index 0000000..831d65a --- /dev/null +++ b/AupInfo.Wpf/ViewModels/PanelItemViewModel.cs @@ -0,0 +1,53 @@ +using System.Reactive.Disposables; +using System.Windows.Input; +using Prism.Mvvm; +using Reactive.Bindings; + +namespace AupInfo.Wpf.ViewModels +{ + public class PanelItemViewModel : BindableBase, IDisposable + { + public string Name { get; } + public string Category { get; } + public string Navigation { get; } + + public ReactiveCommand PreviewMouseLeftButtonUp { get; } + + private readonly CompositeDisposable disposables = new(); + + public PanelItemViewModel( + string name, string category, string navigation, + ReactiveCommand previewMouseLeftButtonUp) + { + Name = name; + Category = category; + Navigation = navigation; + + PreviewMouseLeftButtonUp = previewMouseLeftButtonUp; + } + + #region IDisposable + + private bool disposedValue; + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + disposables.Dispose(); + } + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + #endregion + } +} diff --git a/AupInfo.Wpf/Views/EditHandlePanel.xaml b/AupInfo.Wpf/Views/EditHandlePanel.xaml new file mode 100644 index 0000000..87ff138 --- /dev/null +++ b/AupInfo.Wpf/Views/EditHandlePanel.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/AupInfo.Wpf/Views/EditHandlePanel.xaml.cs b/AupInfo.Wpf/Views/EditHandlePanel.xaml.cs new file mode 100644 index 0000000..cf38858 --- /dev/null +++ b/AupInfo.Wpf/Views/EditHandlePanel.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows.Controls; + +namespace AupInfo.Wpf.Views +{ + /// + /// EditHandlePanel.xaml の相互作用ロジック + /// + public partial class EditHandlePanel : UserControl + { + public EditHandlePanel() + { + InitializeComponent(); + } + } +} diff --git a/AupInfo.Wpf/Views/FilterProjectPanel.xaml b/AupInfo.Wpf/Views/FilterProjectPanel.xaml new file mode 100644 index 0000000..7235fd0 --- /dev/null +++ b/AupInfo.Wpf/Views/FilterProjectPanel.xaml @@ -0,0 +1,15 @@ + + + + + diff --git a/AupInfo.Wpf/Views/FilterProjectPanel.xaml.cs b/AupInfo.Wpf/Views/FilterProjectPanel.xaml.cs new file mode 100644 index 0000000..a32c859 --- /dev/null +++ b/AupInfo.Wpf/Views/FilterProjectPanel.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows.Controls; + +namespace AupInfo.Wpf.Views +{ + /// + /// FilterProjectPanel.xaml の相互作用ロジック + /// + public partial class FilterProjectPanel : UserControl + { + public FilterProjectPanel() + { + InitializeComponent(); + } + } +} diff --git a/AupInfo.Wpf/Views/MainWindow.xaml b/AupInfo.Wpf/Views/MainWindow.xaml index bdb7fe6..6a9ff05 100644 --- a/AupInfo.Wpf/Views/MainWindow.xaml +++ b/AupInfo.Wpf/Views/MainWindow.xaml @@ -7,6 +7,7 @@ xmlns:metro="http://metro.mahapps.com/winfx/xaml/controls" xmlns:prism="http://prismlibrary.com/" xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:rp="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF" xmlns:vm="clr-namespace:AupInfo.Wpf.ViewModels" xmlns:local="clr-namespace:AupInfo.Wpf" prism:ViewModelLocator.AutoWireViewModel="True" @@ -24,8 +25,96 @@ + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2687be6d25321d0867b74afdc492bf1f5dc64cce Mon Sep 17 00:00:00 2001 From: karoterra Date: Sun, 16 Jan 2022 17:23:09 +0900 Subject: [PATCH 03/24] =?UTF-8?q?:sparkles:=20feat:=20=E3=82=A6=E3=82=A3?= =?UTF-8?q?=E3=83=B3=E3=83=89=E3=82=A6=E3=81=ABD&D=E3=81=97=E3=81=9Faup?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92=E9=96=8B=E3=81=8F?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AupInfo.Core/AupFile.cs | 108 ++++++++++++++++++ AupInfo.Core/AupInfo.Core.csproj | 15 +++ AupInfo.Core/CoreModule.cs | 17 +++ AupInfo.Wpf/App.xaml.cs | 9 +- AupInfo.Wpf/AupInfo.Wpf.csproj | 4 + .../ViewModels/EditHandlePanelViewModel.cs | 2 +- .../ViewModels/FilterProjectPanelViewModel.cs | 2 +- AupInfo.Wpf/ViewModels/MainWindowViewModel.cs | 90 ++++++++++++++- AupInfo.Wpf/ViewModels/PanelItemViewModel.cs | 5 +- AupInfo.Wpf/Views/MainWindow.xaml | 34 +++++- AupInfo.sln | 6 + 11 files changed, 280 insertions(+), 12 deletions(-) create mode 100644 AupInfo.Core/AupFile.cs create mode 100644 AupInfo.Core/AupInfo.Core.csproj create mode 100644 AupInfo.Core/CoreModule.cs diff --git a/AupInfo.Core/AupFile.cs b/AupInfo.Core/AupFile.cs new file mode 100644 index 0000000..79541e4 --- /dev/null +++ b/AupInfo.Core/AupFile.cs @@ -0,0 +1,108 @@ +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Karoterra.AupDotNet; +using Karoterra.AupDotNet.ExEdit; +using Reactive.Bindings; +using Reactive.Bindings.Extensions; + +namespace AupInfo.Core +{ + public class AupFile : IDisposable + { + public ReadOnlyReactivePropertySlim FilePath { get; } + public ReadOnlyReactivePropertySlim FileName { get; } + + public ReactivePropertySlim EditHandle { get; } + public ReactiveCollection FilterProjects { get; } + public ReactivePropertySlim ExEdit { get; } + + public ReactiveCommand Opened { get; } + + private readonly ReactivePropertySlim filepath; + private AviUtlProject? aup = null; + private readonly CompositeDisposable disposables = new(); + + public AupFile() + { + filepath = new ReactivePropertySlim(null) + .AddTo(disposables); + + FilePath = filepath.ToReadOnlyReactivePropertySlim() + .AddTo(disposables); + FileName = filepath + .Select(x => Path.GetFileName(x)) + .ToReadOnlyReactivePropertySlim() + .AddTo(disposables); + + EditHandle = new ReactivePropertySlim(null) + .AddTo(disposables); + FilterProjects = new ReactiveCollection() + .AddTo(disposables); + ExEdit = new ReactivePropertySlim(null) + .AddTo(disposables); + + Opened = new ReactiveCommand() + .AddTo(disposables); + } + + public void Open(string path) + { + aup = new(path); + filepath.Value = path; + + FilterProjects.ClearOnScheduler(); + FilterProjects.AddRangeOnScheduler(aup.FilterProjects); + + var filter = aup.FilterProjects.FirstOrDefault(f => f.Name == "拡張編集"); + if (filter != null) + { + ExEdit.Value = new(filter.DumpData()); + } + + Opened.Execute(); + } + + public void Close() + { + aup = null; + ExEdit.Value = null; + FilterProjects.ClearOnScheduler(); + filepath.Value = null; + } + + public void Save(string? path = null) + { + if (aup == null) return; + if (path == null) + path = filepath.Value!; + + using var fs = File.Create(path); + using BinaryWriter bw = new(fs); + aup.Write(bw); + } + + #region IDisposable + + private bool disposedValue; + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + disposables.Dispose(); + } + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + #endregion + } +} diff --git a/AupInfo.Core/AupInfo.Core.csproj b/AupInfo.Core/AupInfo.Core.csproj new file mode 100644 index 0000000..e224188 --- /dev/null +++ b/AupInfo.Core/AupInfo.Core.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/AupInfo.Core/CoreModule.cs b/AupInfo.Core/CoreModule.cs new file mode 100644 index 0000000..d975c9d --- /dev/null +++ b/AupInfo.Core/CoreModule.cs @@ -0,0 +1,17 @@ +using Prism.Ioc; +using Prism.Modularity; + +namespace AupInfo.Core +{ + public class CoreModule : IModule + { + public void OnInitialized(IContainerProvider containerProvider) + { + } + + public void RegisterTypes(IContainerRegistry containerRegistry) + { + containerRegistry.RegisterSingleton(); + } + } +} diff --git a/AupInfo.Wpf/App.xaml.cs b/AupInfo.Wpf/App.xaml.cs index 337de36..9dfe457 100644 --- a/AupInfo.Wpf/App.xaml.cs +++ b/AupInfo.Wpf/App.xaml.cs @@ -1,7 +1,8 @@ using System.Text; using System.Windows; -using Prism.Ioc; using AupInfo.Wpf.Views; +using Prism.Ioc; +using Prism.Modularity; namespace AupInfo.Wpf { @@ -13,6 +14,7 @@ public partial class App protected override Window CreateShell() { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + Container.Resolve().LoadModule(); return Container.Resolve(); } @@ -21,5 +23,10 @@ protected override void RegisterTypes(IContainerRegistry containerRegistry) containerRegistry.RegisterForNavigation(); containerRegistry.RegisterForNavigation(); } + + protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) + { + moduleCatalog.AddModule(InitializationMode.OnDemand); + } } } diff --git a/AupInfo.Wpf/AupInfo.Wpf.csproj b/AupInfo.Wpf/AupInfo.Wpf.csproj index 4c3599d..31117fd 100644 --- a/AupInfo.Wpf/AupInfo.Wpf.csproj +++ b/AupInfo.Wpf/AupInfo.Wpf.csproj @@ -16,4 +16,8 @@ + + + + diff --git a/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs b/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs index 68a13ba..a08a8fb 100644 --- a/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs +++ b/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs @@ -19,7 +19,7 @@ public class EditHandlePanelViewModel : BindableBase, IDestructible public ReactivePropertySlim FrameNum { get; } public ReactivePropertySlim TimeLength { get; } - private CompositeDisposable disposables = new(); + private readonly CompositeDisposable disposables = new(); public EditHandlePanelViewModel() { diff --git a/AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs b/AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs index 226ecc9..67fbc8c 100644 --- a/AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs +++ b/AupInfo.Wpf/ViewModels/FilterProjectPanelViewModel.cs @@ -10,7 +10,7 @@ public class FilterProjectPanelViewModel : BindableBase, IDestructible { public ReactiveCollection Filters { get; } - private CompositeDisposable disposables = new(); + private readonly CompositeDisposable disposables = new(); public FilterProjectPanelViewModel() { diff --git a/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs b/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs index 2487f0b..4a2017e 100644 --- a/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs +++ b/AupInfo.Wpf/ViewModels/MainWindowViewModel.cs @@ -1,11 +1,14 @@ -using System.Reactive.Disposables; +using System.IO; +using System.Reactive.Disposables; using System.Reactive.Linq; +using System.Windows; +using System.Windows.Input; +using AupInfo.Core; using MaterialDesignThemes.Wpf; using Prism.Mvvm; using Prism.Regions; using Reactive.Bindings; using Reactive.Bindings.Extensions; -using System.Windows.Input; namespace AupInfo.Wpf.ViewModels { @@ -13,6 +16,8 @@ public class MainWindowViewModel : BindableBase, IDisposable { public ReactivePropertySlim Title { get; } public ReactivePropertySlim Subtitle { get; } + public ReadOnlyReactivePropertySlim FilePath { get; } + public ReadOnlyReactivePropertySlim Filename { get; } public ReactivePropertySlim IsMenuOpen { get; } public ReactivePropertySlim IsModeless { get; } @@ -24,16 +29,24 @@ public class MainWindowViewModel : BindableBase, IDisposable public ReactiveCommand Loaded { get; } public ReactiveCommand SelectedItemClicked { get; } + public ReactiveCommand Drop { get; } + public ReactiveCommand DragOver { get; } + + public SnackbarMessageQueue SnackbarMessageQueue { get; } = new(); private readonly CompositeDisposable disposables = new(); private readonly IRegionManager regionManager; + private readonly AupFile aup; - public MainWindowViewModel(IRegionManager regionManager) + public MainWindowViewModel(IRegionManager regionManager, AupFile aup) { this.regionManager = regionManager; + this.aup = aup; Title = new ReactivePropertySlim("AupInfo").AddTo(disposables); Subtitle = new ReactivePropertySlim("Title").AddTo(disposables); + FilePath = this.aup.FilePath.ToReadOnlyReactivePropertySlim().AddTo(disposables); + Filename = this.aup.FileName.ToReadOnlyReactivePropertySlim().AddTo(disposables); IsMenuOpen = new ReactivePropertySlim(false).AddTo(disposables); IsModeless = new ReactivePropertySlim(false).AddTo(disposables); PanelItems = new ReactiveCollection().AddTo(disposables); @@ -60,6 +73,23 @@ public MainWindowViewModel(IRegionManager regionManager) }) .AddTo(disposables); + DragOver = new ReactiveCommand() + .WithSubscribe(e => + { + e.Effects = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None; + e.Handled = true; + }) + .AddTo(disposables); + Drop = new ReactiveCommand() + .WithSubscribe(e => + { + if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return; + + var files = e.Data.GetData(DataFormats.FileDrop) as string[]; + OpenAup(files![0]); + }) + .AddTo(disposables); + SelectedItem.Subscribe(item => { if (!string.IsNullOrEmpty(item?.Navigation)) @@ -80,6 +110,60 @@ public MainWindowViewModel(IRegionManager regionManager) PanelItems.Add(new("ファイル", "PSDToolKit", "", SelectedItemClicked)); } + private void OpenAup(string path) + { + if (Directory.Exists(path)) + { + SnackbarMessageQueue.Enqueue($"\"{path}\" はディレクトリです。"); + return; + } + + try + { + aup.Open(path); + SnackbarMessageQueue.Enqueue($"\"{path}\" を開きました。"); + } + catch (FileNotFoundException) + { + SnackbarMessageQueue.Enqueue($"\"{path}\" が見つかりません。"); + aup.Close(); + } + catch (UnauthorizedAccessException) + { + SnackbarMessageQueue.Enqueue($"\"{path}\" へのアクセス許可がありません。"); + aup.Close(); + } + catch (PathTooLongException) + { + SnackbarMessageQueue.Enqueue("パスが長すぎます。"); + aup.Close(); + } + catch (Exception e) when ( + e is ArgumentException or + ArgumentNullException or + DirectoryNotFoundException or + NotSupportedException) + { + SnackbarMessageQueue.Enqueue("有効なパスを指定してください。"); + aup.Close(); + } + catch (FileFormatException) + { + SnackbarMessageQueue.Enqueue($"\"{path}\" はAviUtlプロジェクトファイルでないか破損している可能性があります。"); + aup.Close(); + } + catch (EndOfStreamException) + { + SnackbarMessageQueue.Enqueue($"\"{path}\" はAviUtlプロジェクトファイルでないか破損している可能性があります。"); + aup.Close(); + } + catch (IOException) + { + SnackbarMessageQueue.Enqueue("IOエラーが発生しました。"); + aup.Close(); + } + } + #region IDisposable private bool disposedValue; diff --git a/AupInfo.Wpf/ViewModels/PanelItemViewModel.cs b/AupInfo.Wpf/ViewModels/PanelItemViewModel.cs index 831d65a..aaf881a 100644 --- a/AupInfo.Wpf/ViewModels/PanelItemViewModel.cs +++ b/AupInfo.Wpf/ViewModels/PanelItemViewModel.cs @@ -1,7 +1,6 @@ using System.Reactive.Disposables; using System.Windows.Input; using Prism.Mvvm; -using Reactive.Bindings; namespace AupInfo.Wpf.ViewModels { @@ -11,13 +10,13 @@ public class PanelItemViewModel : BindableBase, IDisposable public string Category { get; } public string Navigation { get; } - public ReactiveCommand PreviewMouseLeftButtonUp { get; } + public ICommand PreviewMouseLeftButtonUp { get; } private readonly CompositeDisposable disposables = new(); public PanelItemViewModel( string name, string category, string navigation, - ReactiveCommand previewMouseLeftButtonUp) + ICommand previewMouseLeftButtonUp) { Name = name; Category = category; diff --git a/AupInfo.Wpf/Views/MainWindow.xaml b/AupInfo.Wpf/Views/MainWindow.xaml index 6a9ff05..41879a5 100644 --- a/AupInfo.Wpf/Views/MainWindow.xaml +++ b/AupInfo.Wpf/Views/MainWindow.xaml @@ -20,7 +20,9 @@ FontFamily="{md:MaterialDesignFont}" BorderThickness="1" TitleCharacterCasing="Normal" - Title="{Binding Title.Value}" Height="450" Width="800"> + TitleAlignment="Center" + Title="{Binding Title.Value}" Height="450" Width="800" + AllowDrop="True"> @@ -28,6 +30,12 @@ + + + + + + @@ -38,7 +46,16 @@ - + + + + + + + @@ -113,7 +130,18 @@ - + + + + + + + + + + diff --git a/AupInfo.sln b/AupInfo.sln index 7ce937c..999c701 100644 --- a/AupInfo.sln +++ b/AupInfo.sln @@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AupInfo.Core", "AupInfo.Core\AupInfo.Core.csproj", "{2EC07FB3-8DA7-457D-86C3-EB3170FA492B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -20,6 +22,10 @@ Global {3BB2D48A-79FB-488E-AAD9-2AD71D716135}.Debug|Any CPU.Build.0 = Debug|Any CPU {3BB2D48A-79FB-488E-AAD9-2AD71D716135}.Release|Any CPU.ActiveCfg = Release|Any CPU {3BB2D48A-79FB-488E-AAD9-2AD71D716135}.Release|Any CPU.Build.0 = Release|Any CPU + {2EC07FB3-8DA7-457D-86C3-EB3170FA492B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2EC07FB3-8DA7-457D-86C3-EB3170FA492B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2EC07FB3-8DA7-457D-86C3-EB3170FA492B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2EC07FB3-8DA7-457D-86C3-EB3170FA492B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 8ee0c47c3dc67e251d3402c7885bc3c3eba2625e Mon Sep 17 00:00:00 2001 From: karoterra Date: Sun, 16 Jan 2022 18:37:53 +0900 Subject: [PATCH 04/24] =?UTF-8?q?:sparkles:=20feat:=20EditHandle=E3=81=AE?= =?UTF-8?q?=E6=83=85=E5=A0=B1=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=82=92=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AupInfo.Core/AupFile.cs | 2 + AupInfo.Wpf/App.xaml | 5 +- .../NullableToVisibilityConverter.cs | 19 ++++ .../ViewModels/EditHandlePanelViewModel.cs | 88 ++++++++++++++----- AupInfo.Wpf/Views/EditHandlePanel.xaml | 46 +++++++--- 5 files changed, 124 insertions(+), 36 deletions(-) create mode 100644 AupInfo.Wpf/Converters/NullableToVisibilityConverter.cs diff --git a/AupInfo.Core/AupFile.cs b/AupInfo.Core/AupFile.cs index 79541e4..53ddedf 100644 --- a/AupInfo.Core/AupFile.cs +++ b/AupInfo.Core/AupFile.cs @@ -48,6 +48,7 @@ public AupFile() public void Open(string path) { aup = new(path); + EditHandle.Value = aup.EditHandle; filepath.Value = path; FilterProjects.ClearOnScheduler(); @@ -66,6 +67,7 @@ public void Close() { aup = null; ExEdit.Value = null; + EditHandle.Value = null; FilterProjects.ClearOnScheduler(); filepath.Value = null; } diff --git a/AupInfo.Wpf/App.xaml b/AupInfo.Wpf/App.xaml index 338fd10..15154e3 100644 --- a/AupInfo.Wpf/App.xaml +++ b/AupInfo.Wpf/App.xaml @@ -1,7 +1,8 @@  + xmlns:prism="http://prismlibrary.com/" + xmlns:converter="clr-namespace:AupInfo.Wpf.Converters"> @@ -37,6 +38,8 @@ + + diff --git a/AupInfo.Wpf/Converters/NullableToVisibilityConverter.cs b/AupInfo.Wpf/Converters/NullableToVisibilityConverter.cs new file mode 100644 index 0000000..3435d19 --- /dev/null +++ b/AupInfo.Wpf/Converters/NullableToVisibilityConverter.cs @@ -0,0 +1,19 @@ +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace AupInfo.Wpf.Converters +{ + public class NullableToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value == null ? Visibility.Collapsed : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs b/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs index a08a8fb..d096ce9 100644 --- a/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs +++ b/AupInfo.Wpf/ViewModels/EditHandlePanelViewModel.cs @@ -1,4 +1,7 @@ using System.Reactive.Disposables; +using System.Reactive.Linq; +using AupInfo.Core; +using Karoterra.AupDotNet.Extensions; using Prism.Mvvm; using Prism.Navigation; using Reactive.Bindings; @@ -8,31 +11,74 @@ namespace AupInfo.Wpf.ViewModels { public class EditHandlePanelViewModel : BindableBase, IDestructible { - public ReactivePropertySlim EditFilename { get; } - public ReactivePropertySlim OutputFilename { get; } - public ReactivePropertySlim ProjectFilename { get; } - public ReactivePropertySlim Width { get; } - public ReactivePropertySlim Height { get; } - public ReactivePropertySlim VideoRate { get; } - public ReactivePropertySlim AudioRate { get; } - public ReactivePropertySlim AudioCh { get; } - public ReactivePropertySlim FrameNum { get; } - public ReactivePropertySlim TimeLength { get; } + public ReactivePropertySlim EditFilename { get; } + public ReactivePropertySlim OutputFilename { get; } + public ReactivePropertySlim ProjectFilename { get; } + public ReactivePropertySlim Width { get; } + public ReactivePropertySlim Height { get; } + public ReactivePropertySlim VideoRate { get; } + public ReactivePropertySlim AudioRate { get; } + public ReactivePropertySlim AudioCh { get; } + public ReactivePropertySlim FrameNum { get; } + public ReactivePropertySlim TimeLength { get; } + public ReactivePropertySlim Flag { get; } + public ReactivePropertySlim SelectedFrameStart { get; } + public ReactivePropertySlim SelectedFrameEnd { get; } + public ReactivePropertySlim VideoDecodeBit { get; } + public ReactivePropertySlim VideoDecodeFormat { get; } private readonly CompositeDisposable disposables = new(); + private readonly AupFile aup; - public EditHandlePanelViewModel() + public EditHandlePanelViewModel(AupFile _aup) { - EditFilename = new ReactivePropertySlim("1920x1080_30fps_44100Hz.exedit").AddTo(disposables); - OutputFilename = new ReactivePropertySlim(@"C:\path\to\video.mp4").AddTo(disposables); - ProjectFilename = new ReactivePropertySlim(@"C:\path\to\project.aup").AddTo(disposables); - Width = new ReactivePropertySlim(1920).AddTo(disposables); - Height = new ReactivePropertySlim(1080).AddTo(disposables); - VideoRate = new ReactivePropertySlim("30").AddTo(disposables); - AudioRate = new ReactivePropertySlim(44100).AddTo(disposables); - AudioCh = new ReactivePropertySlim(2).AddTo(disposables); - FrameNum = new ReactivePropertySlim(120).AddTo(disposables); - TimeLength = new ReactivePropertySlim("00:00:00.000").AddTo(disposables); + aup = _aup; + + EditFilename = new ReactivePropertySlim("1920x1080_30fps_44100Hz.exedit").AddTo(disposables); + OutputFilename = new ReactivePropertySlim(@"C:\path\to\video.mp4").AddTo(disposables); + ProjectFilename = new ReactivePropertySlim(@"C:\path\to\project.aup").AddTo(disposables); + Width = new ReactivePropertySlim(1920).AddTo(disposables); + Height = new ReactivePropertySlim(1080).AddTo(disposables); + VideoRate = new ReactivePropertySlim("30").AddTo(disposables); + AudioRate = new ReactivePropertySlim(44100).AddTo(disposables); + AudioCh = new ReactivePropertySlim(2).AddTo(disposables); + FrameNum = new ReactivePropertySlim(120).AddTo(disposables); + TimeLength = new ReactivePropertySlim("00:00:00.000").AddTo(disposables); + Flag = new ReactivePropertySlim(null).AddTo(disposables); + SelectedFrameStart = new ReactivePropertySlim(0).AddTo(disposables); + SelectedFrameEnd = new ReactivePropertySlim(120).AddTo(disposables); + VideoDecodeBit = new ReactivePropertySlim(48).AddTo(disposables); + VideoDecodeFormat = new ReactivePropertySlim("XXXX").AddTo(disposables); + + aup.EditHandle.Subscribe(edit => + { + EditFilename.Value = edit?.EditFilename; + OutputFilename.Value = edit?.OutputFilename; + ProjectFilename.Value = edit?.ProjectFilename; + Width.Value = edit?.Width; + Height.Value = edit?.Height; + AudioRate.Value = edit?.AudioRate; + AudioCh.Value = edit?.AudioCh; + Flag.Value = edit?.Flag.ToString("X8"); + SelectedFrameStart.Value = edit?.SelectedFrameStart; + SelectedFrameEnd.Value = edit?.SelectedFrameEnd; + VideoDecodeBit.Value = edit?.VideoDecodeBit; + VideoDecodeFormat.Value = edit?.VideoDecodeFormat.ToBytes().ToCleanSjisString(); + if (edit == null) + { + VideoRate.Value = null; + FrameNum.Value = null; + TimeLength.Value = null; + } + else + { + double fps = (double)edit.VideoRate / edit.VideoScale; + VideoRate.Value = fps.ToString(); + FrameNum.Value = edit.Frames.Count; + var ts = new TimeSpan((long)(edit.Frames.Count / fps * 10000000)); + TimeLength.Value = ts.ToString($@"{(ts.Days > 0 ? @"d\." : "")}hh\:mm\:ss\.fff"); + } + }).AddTo(disposables); } public void Destroy() diff --git a/AupInfo.Wpf/Views/EditHandlePanel.xaml b/AupInfo.Wpf/Views/EditHandlePanel.xaml index 87ff138..d810f93 100644 --- a/AupInfo.Wpf/Views/EditHandlePanel.xaml +++ b/AupInfo.Wpf/Views/EditHandlePanel.xaml @@ -26,6 +26,8 @@ + +