From 4f1c92c82b7a2d71d1ff881e4cd2f6f94ebc7d94 Mon Sep 17 00:00:00 2001
From: Hakoyu <Hakoyu@outlook.com>
Date: Wed, 6 Sep 2023 17:22:58 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20SimpleObservable?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../SimpleObservable/ObservableCommand.cs     | 55 ++++++++++---------
 ...bleCommand{T}.cs => ObservableCommandT.cs} | 44 ++++++++-------
 VPet.ModMaker/VPet.ModMaker.csproj            |  2 +-
 .../ModEdit/ClickTextEdit/ClickTextPageVM.cs  |  6 +-
 .../ModEdit/FoodEdit/FoodEditWindowVM.cs      |  4 +-
 .../ViewModels/ModEdit/FoodEdit/FoodPageVM.cs |  6 +-
 .../ModEdit/LowTextEdit/LowTextPageVM.cs      |  6 +-
 .../ViewModels/ModEdit/ModEditWindowVM.cs     | 14 ++---
 VPet.ModMaker/ViewModels/ModMakerWindowVM.cs  |  6 +-
 9 files changed, 77 insertions(+), 66 deletions(-)
 rename VPet.ModMaker/SimpleObservable/{ObservableCommand{T}.cs => ObservableCommandT.cs} (61%)

diff --git a/VPet.ModMaker/SimpleObservable/ObservableCommand.cs b/VPet.ModMaker/SimpleObservable/ObservableCommand.cs
index 5c10db1..3a4a9e3 100644
--- a/VPet.ModMaker/SimpleObservable/ObservableCommand.cs
+++ b/VPet.ModMaker/SimpleObservable/ObservableCommand.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -12,26 +13,8 @@ namespace HKW.HKWViewModels.SimpleObservable;
 /// </summary>
 public class ObservableCommand : ICommand
 {
-    /// <summary>
-    /// 执行的方法
-    /// </summary>
-    public Action? ExecuteAction { get; set; }
-
-    /// <summary>
-    /// 执行的异步方法
-    /// </summary>
-    public Func<Task>? ExecuteActionAsync { get; set; }
-
-    /// <summary>
-    /// 获取能否执行的方法
-    /// </summary>
-    public Func<bool>? CanExecuteAction { get; set; }
-
     /// <summary>
     /// 能执行的属性
-    /// <para>
-    /// 注意: 仅当 <see cref="CanExecuteAction"/> 为 <see langword="null"/> 时, 此属性才会被使用
-    /// </para>
     /// </summary>
     public ObservableValue<bool> CanExecuteProperty { get; } = new(true);
 
@@ -64,9 +47,7 @@ public class ObservableCommand : ICommand
     {
         if (r_waiting.Value is true)
             return false;
-        return CanExecuteAction is null
-            ? CanExecuteProperty.Value
-            : CanExecuteAction?.Invoke() is not false;
+        return CanExecuteProperty.Value;
     }
 
     /// <summary>
@@ -75,7 +56,7 @@ public class ObservableCommand : ICommand
     /// <param name="parameter">参数</param>
     public async void Execute(object? parameter)
     {
-        ExecuteAction?.Invoke();
+        ExecuteEvent?.Invoke();
         await ExecuteAsync();
     }
 
@@ -85,15 +66,39 @@ public class ObservableCommand : ICommand
     /// <returns>等待</returns>
     private async Task ExecuteAsync()
     {
-        if (ExecuteActionAsync is null)
+        if (AsyncExecuteEvent is null)
             return;
         r_waiting.Value = true;
-        await ExecuteActionAsync.Invoke();
+        foreach (
+            var asyncEvent in AsyncExecuteEvent.GetInvocationList().Cast<AsyncExecuteHandler>()
+        )
+            await asyncEvent.Invoke();
         r_waiting.Value = false;
     }
 
     /// <summary>
-    /// 能否执行属性被改变事件
+    /// 能否执行属性改变后事件
     /// </summary>
     public event EventHandler? CanExecuteChanged;
+
+    /// <summary>
+    /// 执行事件
+    /// </summary>
+    public event ExecuteHandler? ExecuteEvent;
+
+    /// <summary>
+    /// 异步执行事件
+    /// </summary>
+    public event AsyncExecuteHandler? AsyncExecuteEvent;
+
+    /// <summary>
+    /// 执行
+    /// </summary>
+    public delegate void ExecuteHandler();
+
+    /// <summary>
+    /// 异步执行
+    /// </summary>
+    /// <returns></returns>
+    public delegate Task AsyncExecuteHandler();
 }
diff --git a/VPet.ModMaker/SimpleObservable/ObservableCommand{T}.cs b/VPet.ModMaker/SimpleObservable/ObservableCommandT.cs
similarity index 61%
rename from VPet.ModMaker/SimpleObservable/ObservableCommand{T}.cs
rename to VPet.ModMaker/SimpleObservable/ObservableCommandT.cs
index 5bdee45..db83d80 100644
--- a/VPet.ModMaker/SimpleObservable/ObservableCommand{T}.cs
+++ b/VPet.ModMaker/SimpleObservable/ObservableCommandT.cs
@@ -14,22 +14,13 @@ namespace HKW.HKWViewModels.SimpleObservable;
 public class ObservableCommand<T> : ICommand
     where T : notnull
 {
-    /// <inheritdoc cref="ObservableCommand.ExecuteAction"/>
-    public Action<T?>? ExecuteAction { get; set; }
-
-    /// <inheritdoc cref="ObservableCommand.ExecuteActionAsync"/>
-    public Func<T?, Task>? ExecuteActionAsync { get; set; }
-
-    /// <inheritdoc cref="ObservableCommand.CanExecuteAction"/>
-    public Func<T?, bool>? CanExecuteAction { get; set; }
-
     /// <inheritdoc cref="ObservableCommand.CanExecuteProperty"/>
     public ObservableValue<bool> CanExecuteProperty { get; } = new(true);
 
     /// <inheritdoc cref="ObservableCommand.r_waiting"/>
     private readonly ObservableValue<bool> r_waiting = new(false);
 
-    /// <inheritdoc cref="ObservableCommand.ObservableCommand()"/>
+    /// <inheritdoc />
     public ObservableCommand()
     {
         CanExecuteProperty.PropertyChanged += InvokeCanExecuteChanged;
@@ -49,29 +40,44 @@ public class ObservableCommand<T> : ICommand
     {
         if (r_waiting.Value is true)
             return false;
-        return CanExecuteAction is null
-            ? CanExecuteProperty.Value
-            : CanExecuteAction?.Invoke((T?)parameter) is not false;
+        return CanExecuteProperty.Value;
     }
 
     /// <inheritdoc cref="ObservableCommand.Execute(object?)"/>
     public async void Execute(object? parameter)
     {
-        ExecuteAction?.Invoke((T?)parameter);
-        await ExecuteAsync((T?)parameter);
+        ExecuteEvent?.Invoke((T?)parameter!);
+        await ExecuteAsync((T?)parameter!);
     }
 
-    /// <inheritdoc cref="ObservableCommand.ExecuteActionAsync()"/>
+    /// <inheritdoc cref="ObservableCommand.ExecuteAsync"/>
     /// <param name="parameter">参数</param>
-    private async Task ExecuteAsync(T? parameter)
+    private async Task ExecuteAsync(T parameter)
     {
-        if (ExecuteActionAsync is null)
+        if (AsyncExecuteEvent is null)
             return;
         r_waiting.Value = true;
-        await ExecuteActionAsync.Invoke(parameter);
+        foreach (
+            var asyncEvent in AsyncExecuteEvent.GetInvocationList().Cast<AsyncExecuteHandler>()
+        )
+            await asyncEvent.Invoke(parameter);
         r_waiting.Value = false;
     }
 
     /// <inheritdoc cref="ObservableCommand.CanExecuteChanged"/>
     public event EventHandler? CanExecuteChanged;
+
+    /// <inheritdoc cref="ObservableCommand.ExecuteEvent"/>
+    public event ExecuteHandler? ExecuteEvent;
+
+    /// <inheritdoc cref="ObservableCommand.AsyncExecuteEvent"/>
+    public event AsyncExecuteHandler? AsyncExecuteEvent;
+
+    /// <inheritdoc cref="ObservableCommand.ExecuteHandler"/>
+    /// <param name="value">值</param>
+    public delegate void ExecuteHandler(T value);
+
+    /// <inheritdoc cref="ObservableCommand.AsyncExecuteHandler"/>
+    /// <param name="value">值</param>
+    public delegate Task AsyncExecuteHandler(T value);
 }
diff --git a/VPet.ModMaker/VPet.ModMaker.csproj b/VPet.ModMaker/VPet.ModMaker.csproj
index 955df78..7d2a622 100644
--- a/VPet.ModMaker/VPet.ModMaker.csproj
+++ b/VPet.ModMaker/VPet.ModMaker.csproj
@@ -102,6 +102,7 @@
     <Compile Include="Models\ObservableRange.cs" />
     <Compile Include="Models\PetModel.cs" />
     <Compile Include="Models\SelectTextModel.cs" />
+    <Compile Include="SimpleObservable\ObservableCommandT.cs" />
     <Compile Include="ViewModels\ModEdit\ClickTextEdit\ClickTextEditWindowVM.cs" />
     <Compile Include="ViewModels\ModEdit\ClickTextEdit\ClickTextPageVM.cs" />
     <Compile Include="ViewModels\ModEdit\FoodEdit\FoodPageVM.cs" />
@@ -145,7 +146,6 @@
       <DesignTimeSharedInput>True</DesignTimeSharedInput>
     </Compile>
     <Compile Include="SimpleObservable\ObservableCommand.cs" />
-    <Compile Include="SimpleObservable\ObservableCommand{T}.cs" />
     <Compile Include="SimpleObservable\ObservableValue.cs" />
     <Compile Include="Utils.cs" />
     <Compile Include="Views\ModEdit\FoodEdit\FoodEditWindow.xaml.cs">
diff --git a/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs
index 7aa697e..a2f1eb9 100644
--- a/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs
+++ b/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs
@@ -29,9 +29,9 @@ public class ClickTextPageVM
     {
         ShowClickTexts.Value = ClickTexts;
         FilterClickText.ValueChanged += FilterClickText_ValueChanged;
-        AddClickTextCommand.ExecuteAction = AddClickText;
-        EditClickTextCommand.ExecuteAction = EditClickText;
-        RemoveClickTextCommand.ExecuteAction = RemoveClickText;
+        AddClickTextCommand.ExecuteEvent += AddClickText;
+        EditClickTextCommand.ExecuteEvent += EditClickText;
+        RemoveClickTextCommand.ExecuteEvent += RemoveClickText;
     }
 
     private void FilterClickText_ValueChanged(string value)
diff --git a/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodEditWindowVM.cs
index ab21b8a..3aec3ca 100644
--- a/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodEditWindowVM.cs
+++ b/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodEditWindowVM.cs
@@ -29,8 +29,8 @@ public class FoodEditWindowVM
     public FoodEditWindowVM()
     {
         InitializeFoodTypes();
-        AddImageCommand.ExecuteAction = AddImage;
-        ChangeImageCommand.ExecuteAction = ChangeImage;
+        AddImageCommand.ExecuteEvent += AddImage;
+        ChangeImageCommand.ExecuteEvent += ChangeImage;
     }
 
     public void Close() { }
diff --git a/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodPageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodPageVM.cs
index 124486e..4d6fb92 100644
--- a/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodPageVM.cs
+++ b/VPet.ModMaker/ViewModels/ModEdit/FoodEdit/FoodPageVM.cs
@@ -31,9 +31,9 @@ public class FoodPageVM
         ShowFoods.Value = Foods;
         FilterFoodText.ValueChanged += FilterFoodText_ValueChanged;
 
-        AddFoodCommand.ExecuteAction = AddFood;
-        EditFoodCommand.ExecuteAction = EditFood;
-        RemoveFoodCommand.ExecuteAction = RemoveFood;
+        AddFoodCommand.ExecuteEvent += AddFood;
+        EditFoodCommand.ExecuteEvent += EditFood;
+        RemoveFoodCommand.ExecuteEvent += RemoveFood;
     }
 
     private void FilterFoodText_ValueChanged(string value)
diff --git a/VPet.ModMaker/ViewModels/ModEdit/LowTextEdit/LowTextPageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/LowTextEdit/LowTextPageVM.cs
index 2474c77..12f072a 100644
--- a/VPet.ModMaker/ViewModels/ModEdit/LowTextEdit/LowTextPageVM.cs
+++ b/VPet.ModMaker/ViewModels/ModEdit/LowTextEdit/LowTextPageVM.cs
@@ -32,9 +32,9 @@ public class LowTextPageVM
     {
         ShowLowTexts.Value = LowTexts;
         FilterLowText.ValueChanged += FilterLowText_ValueChanged;
-        AddLowTextCommand.ExecuteAction = AddLowText;
-        EditLowTextCommand.ExecuteAction = EditLowText;
-        RemoveLowTextCommand.ExecuteAction = RemoveLowText;
+        AddLowTextCommand.ExecuteEvent += AddLowText;
+        EditLowTextCommand.ExecuteEvent += EditLowText;
+        RemoveLowTextCommand.ExecuteEvent += RemoveLowText;
     }
 
     private void FilterLowText_ValueChanged(string value)
diff --git a/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs
index 44a5436..92913b1 100644
--- a/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs
+++ b/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs
@@ -79,13 +79,13 @@ public class ModEditWindowVM
         ModEditWindow = window;
         CurrentLang.ValueChanged += CurrentLang_ValueChanged;
 
-        AddImageCommand.ExecuteAction += AddImage;
-        ChangeImageCommand.ExecuteAction += ChangeImage;
-        AddLangCommand.ExecuteAction += AddLang;
-        EditLangCommand.ExecuteAction += EditLang;
-        RemoveLangCommand.ExecuteAction += RemoveLang;
-        SaveCommand.ExecuteAction += Save;
-        SaveToCommand.ExecuteAction += SaveTo;
+        AddImageCommand.ExecuteEvent += AddImage;
+        ChangeImageCommand.ExecuteEvent += ChangeImage;
+        AddLangCommand.ExecuteEvent += AddLang;
+        EditLangCommand.ExecuteEvent += EditLang;
+        RemoveLangCommand.ExecuteEvent += RemoveLang;
+        SaveCommand.ExecuteEvent += Save;
+        SaveToCommand.ExecuteEvent += SaveTo;
     }
 
     private void CurrentLang_ValueChanged(string value)
diff --git a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs
index 4adc76f..cd73fb8 100644
--- a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs
+++ b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs
@@ -42,9 +42,9 @@ public class ModMakerWindowVM
         LoadHistories();
         ModMakerWindow = window;
         ShowHistories.Value = Histories;
-        CreateNewModCommand.ExecuteAction = CreateNewMod;
-        LoadModFromFileCommand.ExecuteAction = LoadModFromFile;
-        ClearHistoriesCommand.ExecuteAction = ClearHistories;
+        CreateNewModCommand.ExecuteEvent += CreateNewMod;
+        LoadModFromFileCommand.ExecuteEvent += LoadModFromFile;
+        ClearHistoriesCommand.ExecuteEvent += ClearHistories;
         HistoriesFilterText.ValueChanged += ModFilterText_ValueChanged;
     }