• R/O
  • HTTP
  • SSH
  • HTTPS

コミット

タグ
未設定

よく使われているワード(クリックで追加)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

なろうブックマーク分析用ツールのPrism+WinUI3サンプル実装


コミットメタ情報

リビジョン71ec7075978b32b6f50058d8f72c8b0ac870b142 (tree)
日時2022-08-18 00:28:38
作者yoshy <yoshy.org.bitbucket@gz.j...>
コミッターyoshy

ログメッセージ

[UPD] アプリケーション終了時に各 ViewModel を明示的に破棄するようにした

変更サマリ

差分

--- a/TestNarou3.Adaptor/Boundary/Gateway/ViewModel/IMainWindowViewModel.cs
+++ b/TestNarou3.Adaptor/Boundary/Gateway/ViewModel/IMainWindowViewModel.cs
@@ -7,6 +7,7 @@ namespace TestNarou3.Adaptor.Boundary.Gateway.ViewModel
77 public static readonly string REGION_NAME = "MainContentPane";
88
99 ReactiveProperty<string> Title { get; }
10- ReactiveCommand CommandClosed { get; }
10+
11+ void OnClosing();
1112 }
1213 }
\ No newline at end of file
--- a/TestNarou3.Adaptor/Gateway/ViewModel/BookmarkCategoryViewModel.cs
+++ b/TestNarou3.Adaptor/Gateway/ViewModel/BookmarkCategoryViewModel.cs
@@ -16,7 +16,7 @@ using TestNarou3.Domain.Model.Entity.Child;
1616 namespace TestNarou3.Adaptor.Gateway.ViewModel
1717 {
1818 internal class BookmarkCategoryViewModel
19- : IBookmarkCategoryViewModel, INotifyPropertyChanged, IDestructible
19+ : IBookmarkCategoryViewModel, INotifyPropertyChanged, IDestructible, IDisposable
2020 {
2121 private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
2222
@@ -33,7 +33,9 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
3333 public IAppWindowController WindowController { get; }
3434
3535 private readonly IBookmarkCategoryRowViewModelTranslator vmTranslator;
36+
3637 private readonly CompositeDisposable disposables = new();
38+ private bool disposedValue;
3739
3840 public BookmarkCategoryViewModel(
3941 IAppWindowController wc,
@@ -46,6 +48,8 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
4648 this.SelectedItem.Subscribe(OnSelectedItemChanged).AddTo(disposables);
4749 }
4850
51+ #region event handler
52+
4953 private void OnSelectedItemChanged(IBookmarkCategoryRowViewModel row)
5054 {
5155 if (row == null)
@@ -55,6 +59,10 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
5559 this.WindowController.NavigateBookmarkListView(row.Index);
5660 }
5761
62+ #endregion
63+
64+ #region vm operation
65+
5866 public void SynchronizeWith(BookmarkCategory source)
5967 {
6068 if (this.Source == null)
@@ -83,10 +91,55 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
8391 }
8492 }
8593
94+ #endregion
95+
96+ #region IDestructible
97+
8698 public void Destroy()
8799 {
88- this.disposables.Dispose();
100+ this.Dispose();
89101 }
90102
103+ #endregion
104+
105+ #region IDisposable
106+
107+ protected virtual void Dispose(bool disposing)
108+ {
109+ if (!disposedValue)
110+ {
111+ if (disposing)
112+ {
113+ DisposeSynchronizedView();
114+
115+ this.disposables.Dispose();
116+
117+ logger.Trace("BookmarkCategoryViewModel disposed.");
118+ }
119+
120+ disposedValue = true;
121+ }
122+ }
123+
124+ private void DisposeSynchronizedView()
125+ {
126+ foreach (var row in this.Rows)
127+ {
128+ if (row is IDisposable disposable)
129+ {
130+ disposable.Dispose();
131+ }
132+ }
133+ }
134+
135+ public void Dispose()
136+ {
137+ // このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
138+ Dispose(disposing: true);
139+ GC.SuppressFinalize(this);
140+ }
141+
142+ #endregion
143+
91144 }
92145 }
--- a/TestNarou3.Adaptor/Gateway/ViewModel/BookmarkDetailListViewModel.cs
+++ b/TestNarou3.Adaptor/Gateway/ViewModel/BookmarkDetailListViewModel.cs
@@ -17,7 +17,7 @@ using TestNarou3.Domain.Model.Entity.Child;
1717 namespace TestNarou3.Adaptor.Gateway.ViewModel
1818 {
1919 internal class BookmarkDetailListViewModel
20- : IBookmarkDetailListViewModel, INotifyPropertyChanged, IDestructible
20+ : IBookmarkDetailListViewModel, INotifyPropertyChanged, IDestructible, IDisposable
2121 {
2222 private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
2323
@@ -36,9 +36,10 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
3636 private IAppWindowController WindowController { get; }
3737
3838 private IBookmarkDetailListRowViewModel selectedRow;
39-
4039 private readonly IBookmarkDetailListRowViewModelTranslator vmTranslator;
40+
4141 private readonly CompositeDisposable disposables = new();
42+ private bool disposedValue;
4243
4344 public BookmarkDetailListViewModel(
4445 IAppWindowController wc,
@@ -54,6 +55,8 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
5455 .WithSubscribe(OpenBookmark).AddTo(disposables);
5556 }
5657
58+ #region event handler
59+
5760 private void OnSelectedItemChanged(IBookmarkDetailListRowViewModel selectedRow)
5861 {
5962 this.selectedRow = selectedRow;
@@ -74,6 +77,10 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
7477 Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
7578 }
7679
80+ #endregion
81+
82+ #region vm operation
83+
7784 public void SynchronizeWith(BookmarkDetailList source)
7885 {
7986 if (this.Source == null)
@@ -96,10 +103,55 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
96103 }
97104 }
98105
106+ #endregion
107+
108+ #region IDestructible
109+
99110 public void Destroy()
100111 {
101- this.disposables.Dispose();
112+ this.Dispose();
113+ }
114+
115+ #endregion
116+
117+ #region IDisposable
118+
119+ protected virtual void Dispose(bool disposing)
120+ {
121+ if (!disposedValue)
122+ {
123+ if (disposing)
124+ {
125+ DisposeSynchronizedView();
126+
127+ this.disposables.Dispose();
128+
129+ logger.Trace("BookmarkDetailListViewModel disposed.");
130+ }
131+
132+ disposedValue = true;
133+ }
134+ }
135+
136+ private void DisposeSynchronizedView()
137+ {
138+ foreach (var row in this.Rows)
139+ {
140+ if (row is IDisposable disposable)
141+ {
142+ disposable.Dispose();
143+ }
144+ }
145+ }
146+
147+ public void Dispose()
148+ {
149+ // このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
150+ Dispose(disposing: true);
151+ GC.SuppressFinalize(this);
102152 }
103153
154+ #endregion
155+
104156 }
105157 }
--- a/TestNarou3.Adaptor/Gateway/ViewModel/BookmarkViewModel.cs
+++ b/TestNarou3.Adaptor/Gateway/ViewModel/BookmarkViewModel.cs
@@ -1,24 +1,56 @@
1-using Prism.Navigation;
1+using NLog;
2+using Prism.Navigation;
23 using System.ComponentModel;
34 using System.Reactive.Disposables;
45 using TestNarou3.Adaptor.Boundary.Gateway.ViewModel;
56
67 namespace TestNarou3.Adaptor.Gateway.ViewModel
78 {
8- internal class BookmarkViewModel : IBookmarkViewModel, IDestructible
9+ internal class BookmarkViewModel : IBookmarkViewModel, IDestructible, IDisposable
910 {
10- //private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
11+ private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
1112
1213 #pragma warning disable CS0067
1314 public event PropertyChangedEventHandler PropertyChanged;
1415 #pragma warning restore CS0067
1516
1617 private readonly CompositeDisposable disposables = new();
18+ private bool disposedValue;
19+
20+ #region IDestructible
1721
1822 public void Destroy()
1923 {
20- this.disposables.Dispose();
24+ this.Dispose();
25+ }
26+
27+ #endregion
28+
29+ #region IDisposable
30+
31+ protected virtual void Dispose(bool disposing)
32+ {
33+ if (!disposedValue)
34+ {
35+ if (disposing)
36+ {
37+ this.disposables.Dispose();
38+
39+ logger.Trace("BookmarkViewModel disposed.");
40+ }
41+
42+ disposedValue = true;
43+ }
44+ }
45+
46+ public void Dispose()
47+ {
48+ // このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
49+ Dispose(disposing: true);
50+ GC.SuppressFinalize(this);
2151 }
2252
53+ #endregion
54+
2355 }
2456 }
--- a/TestNarou3.Adaptor/Gateway/ViewModel/LoginFormViewModel.cs
+++ b/TestNarou3.Adaptor/Gateway/ViewModel/LoginFormViewModel.cs
@@ -11,7 +11,7 @@ using TestNarou3.UseCase.Request;
1111
1212 namespace TestNarou3.Adaptor.Gateway.ViewModel
1313 {
14- internal class LoginFormViewModel : ILoginFormViewModel, IDestructible
14+ internal class LoginFormViewModel : ILoginFormViewModel, IDestructible, IDisposable
1515 {
1616 private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
1717
@@ -26,6 +26,7 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
2626 private readonly IAppWindowController wc;
2727
2828 private readonly CompositeDisposable disposables = new();
29+ private bool disposedValue;
2930
3031 public LoginFormViewModel(IAppWindowController wc)
3132 {
@@ -37,11 +38,41 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
3738 this.CommandLogin = new ReactiveCommand().WithSubscribe(OnLogin).AddTo(disposables);
3839 }
3940
41+ #region IDestructible
42+
4043 public void Destroy()
4144 {
42- this.disposables.Dispose();
45+ this.Dispose();
4346 }
4447
48+ #endregion
49+
50+ #region IDisposable
51+
52+ protected virtual void Dispose(bool disposing)
53+ {
54+ if (!disposedValue)
55+ {
56+ if (disposing)
57+ {
58+ this.disposables.Dispose();
59+
60+ logger.Trace("LoginFormViewModel disposed.");
61+ }
62+
63+ disposedValue = true;
64+ }
65+ }
66+
67+ public void Dispose()
68+ {
69+ // このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
70+ Dispose(disposing: true);
71+ GC.SuppressFinalize(this);
72+ }
73+
74+ #endregion
75+
4576 #region event handler
4677
4778 private void OnLogin()
@@ -72,5 +103,6 @@ namespace TestNarou3.Adaptor.Gateway.ViewModel
72103 }
73104
74105 #endregion
106+
75107 }
76108 }
--- a/TestNarou3.Adaptor/Gateway/ViewModel/MainWindowViewModel.cs
+++ b/TestNarou3.Adaptor/Gateway/ViewModel/MainWindowViewModel.cs
@@ -1,4 +1,6 @@
1-using Prism.Navigation;
1+using NLog;
2+using Prism.Navigation;
3+using Prism.Regions;
24 using Reactive.Bindings;
35 using Reactive.Bindings.Extensions;
46 using System.Reactive.Disposables;
@@ -9,37 +11,75 @@ using TestNarou3.UseCase.Request;
911
1012 namespace TestNarou3.Adaptor.Gateway.ViewModel
1113 {
12- internal class MainWindowViewModel : IMainWindowViewModel, IDestructible
14+ internal class MainWindowViewModel : IMainWindowViewModel, IDestructible, IDisposable
1315 {
14- private IAppWindowController wc;
16+ private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
1517
1618 public ReactiveProperty<string> Title { get; }
1719
18- public ReactiveCommand CommandClosed { get; }
20+ private readonly IAppWindowController wc;
21+ private readonly IRegionManager rm;
1922
2023 private readonly CompositeDisposable disposables = new();
24+ private bool disposedValue;
2125
2226 public MainWindowViewModel(
2327 IAppCaptionFormatter caption,
24- IAppWindowController wc)
28+ IAppWindowController wc,
29+ IRegionManager rm)
2530 {
2631 this.wc = wc;
32+ this.rm = rm;
2733
2834 this.Title = new ReactiveProperty<string>(caption.GetCaption()).AddTo(disposables);
29-
30- this.CommandClosed = new ReactiveCommand().WithSubscribe(OnClosed).AddTo(disposables);
3135 }
3236
33- private void OnClosed()
37+ public void OnClosing()
3438 {
3539 _ = this.wc.Execute(new NarouLogoutRequest());
3640 _ = this.wc.Execute(new AppConfigSaveRequest());
41+
42+ this.Dispose();
3743 }
3844
45+ #region IDestructible
46+
3947 public void Destroy()
4048 {
41- this.disposables.Dispose();
49+ this.Dispose();
50+ }
51+
52+ #endregion
53+
54+ #region IDisposable
55+
56+ protected virtual void Dispose(bool disposing)
57+ {
58+ if (!disposedValue)
59+ {
60+ if (disposing)
61+ {
62+ this.disposables.Dispose();
63+
64+ logger.Trace("MainWindowViewModel disposed.");
65+
66+ foreach (IRegion region in rm.Regions)
67+ {
68+ region.RemoveAll();
69+ }
70+ }
71+
72+ disposedValue = true;
73+ }
74+ }
75+
76+ public void Dispose()
77+ {
78+ // このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
79+ Dispose(disposing: true);
80+ GC.SuppressFinalize(this);
4281 }
82+ #endregion
4383
4484 }
4585 }
--- a/TestNarou3.OuterEdge/UI/View/MainWindowView.xaml.cs
+++ b/TestNarou3.OuterEdge/UI/View/MainWindowView.xaml.cs
@@ -10,6 +10,7 @@ using System.Collections.Generic;
1010 using System.IO;
1111 using System.Linq;
1212 using System.Runtime.InteropServices.WindowsRuntime;
13+using TestNarou3.Adaptor.Boundary.Gateway.ViewModel;
1314 using Windows.Foundation;
1415 using Windows.Foundation.Collections;
1516
@@ -20,8 +21,12 @@ namespace TestNarou3.OuterEdge.UI.View
2021 {
2122 public sealed partial class MainWindowView : UserControl
2223 {
23- public MainWindowView()
24+ public IMainWindowViewModel ViewModel { get; }
25+
26+ public MainWindowView(IMainWindowViewModel viewModel)
2427 {
28+ this.ViewModel = viewModel;
29+
2530 this.InitializeComponent();
2631 }
2732 }
--- a/TestNarou3/App.xaml.cs
+++ b/TestNarou3/App.xaml.cs
@@ -3,6 +3,8 @@
33 using AutoMapper;
44 using CleanAuLait;
55 using CleanAuLait.Core.Log;
6+using Microsoft.UI;
7+using Microsoft.UI.Windowing;
68 using Microsoft.UI.Xaml;
79 using Microsoft.UI.Xaml.Controls;
810 using NLog;
@@ -14,6 +16,7 @@ using System.Reflection;
1416 using System.Threading.Tasks;
1517 using TestNarou3.Adaptor;
1618 using TestNarou3.Adaptor.Boundary.Controller;
19+using TestNarou3.Adaptor.Boundary.Gateway.ViewModel;
1720 using TestNarou3.Core.Mapper;
1821 using TestNarou3.Domain;
1922 using TestNarou3.Infra;
@@ -243,6 +246,9 @@ public partial class App : PrismApplication
243246
244247 PrepareInitialView();
245248
249+ AppWindow appWindow = GetCurrentAppWindow();
250+ appWindow.Closing += OnClosing;
251+
246252 logger.Trace("OnStartup end");
247253 }
248254
@@ -257,6 +263,24 @@ public partial class App : PrismApplication
257263 wc.NavigateLoginFormView();
258264 }
259265
266+ private AppWindow GetCurrentAppWindow()
267+ {
268+ IntPtr hwnd = WinRT.Interop.WindowNative.GetWindowHandle(MainWindow);
269+ WindowId winId = Win32Interop.GetWindowIdFromWindow(hwnd);
270+
271+ return AppWindow.GetFromWindowId(winId);
272+ }
273+
274+ private void OnClosing(AppWindow sender, AppWindowClosingEventArgs args)
275+ {
276+ logger.Trace("OnClosing called.");
277+
278+ var vm = Container.Resolve<IMainWindowViewModel>();
279+ vm.OnClosing();
280+
281+ LogManager.Shutdown();
282+ }
283+
260284 #if false
261285 protected override void OnExit(ExitEventArgs e)
262286 {