なろうブックマーク分析用ツールのPrism+WPFサンプル実装
Revisão | 237d5d40225eea9561135640d7467d241705092c (tree) |
---|---|
Hora | 2022-08-06 15:31:53 |
Autor | yoshy <yoshy.org.bitbucket@gz.j...> |
Commiter | yoshy |
[ADD] ブックマーク詳細リストをカテゴリNoごとにキャッシュする機能を追加
@@ -58,7 +58,7 @@ namespace TestNarou.Adaptor | ||
58 | 58 | containerRegistry.RegisterSingleton<IBookmarkViewModel, BookmarkViewModel>(); |
59 | 59 | |
60 | 60 | containerRegistry.RegisterSingleton<IBookmarkCategoryViewModel, BookmarkCategoryViewModel>(); |
61 | - containerRegistry.RegisterSingleton<IBookmarkDetailListViewModel, BookmarkDetailListViewModel>(); | |
61 | + containerRegistry.Register<IBookmarkDetailListViewModel, BookmarkDetailListViewModel>(); | |
62 | 62 | |
63 | 63 | // |
64 | 64 | // Translators |
@@ -1,4 +1,6 @@ | ||
1 | 1 | using CleanAuLait.Adaptor.Boundary.Controller; |
2 | +using TestNarou.Adaptor.Boundary.Gateway.ViewModel; | |
3 | +using TestNarou.Domain.Model.Entity; | |
2 | 4 | |
3 | 5 | namespace TestNarou.Adaptor.Boundary.Controller |
4 | 6 | { |
@@ -6,5 +8,10 @@ namespace TestNarou.Adaptor.Boundary.Controller | ||
6 | 8 | { |
7 | 9 | void NavigateLoginFormView(); |
8 | 10 | void NavigateBookmarkView(); |
11 | + | |
12 | + bool ContainsCategoryNo(int categoryNo); | |
13 | + void RegisterDetailList(int categoryNo, IBookmarkDetailListViewModel vm); | |
14 | + void NavigateBookmarkListView(int index); | |
15 | + void SynchronizeBookmarkDetailList(int categoryNo, BookmarkDetailList detailList); | |
9 | 16 | } |
10 | 17 | } |
@@ -1,4 +1,5 @@ | ||
1 | 1 | using Reactive.Bindings; |
2 | +using System; | |
2 | 3 | using System.ComponentModel; |
3 | 4 | using TestNarou.Adaptor.Boundary.Gateway.ViewModel.Child; |
4 | 5 | using TestNarou.Domain.Model.Entity; |
@@ -7,6 +8,10 @@ namespace TestNarou.Adaptor.Boundary.Gateway.ViewModel | ||
7 | 8 | { |
8 | 9 | public interface IBookmarkDetailListViewModel |
9 | 10 | { |
11 | + internal const string CATEGORY_NO_KEY = "CATEGORY_NO"; | |
12 | + | |
13 | + internal static readonly Uri URI = new("BookmarkDetailListView", UriKind.Relative); | |
14 | + | |
10 | 15 | ReactiveCommand CommandOpenBookmark { get; } |
11 | 16 | ICollectionView Rows { get; } |
12 | 17 | BookmarkDetailList Source { get; } |
@@ -1,15 +1,25 @@ | ||
1 | 1 | using CleanAuLait.Adaptor.Boundary.Controller; |
2 | 2 | using CleanAuLait.Adaptor.Controller; |
3 | 3 | using CleanAuLait.Core.DI; |
4 | +using CleanAuLait.Core.Log; | |
5 | +using NLog; | |
4 | 6 | using Prism.Regions; |
7 | +using System.Collections.Generic; | |
5 | 8 | using TestNarou.Adaptor.Boundary.Controller; |
6 | 9 | using TestNarou.Adaptor.Boundary.Gateway.ViewModel; |
10 | +using TestNarou.Domain.Model.Entity; | |
11 | +using TestNarou.UseCase.Request; | |
7 | 12 | |
8 | 13 | namespace TestNarou.Adaptor.Controller |
9 | 14 | { |
10 | 15 | internal class AppWindowController |
11 | 16 | : AbstractWindowController, IAppWindowController |
12 | 17 | { |
18 | + private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); | |
19 | + | |
20 | + private IDictionary<int, IBookmarkDetailListViewModel> CategoryNoMap { get; } | |
21 | + = new Dictionary<int, IBookmarkDetailListViewModel>(); | |
22 | + | |
13 | 23 | private readonly IRegionManager rm; |
14 | 24 | |
15 | 25 | public AppWindowController( |
@@ -23,14 +33,66 @@ namespace TestNarou.Adaptor.Controller | ||
23 | 33 | |
24 | 34 | public void NavigateLoginFormView() |
25 | 35 | { |
36 | + logger.Trace("NavigateLoginFormView"); | |
37 | + | |
26 | 38 | this.rm.RequestNavigate( |
27 | 39 | IMainWindowViewModel.REGION_NAME, ILoginFormViewModel.URI); |
28 | 40 | } |
29 | 41 | |
30 | 42 | public void NavigateBookmarkView() |
31 | 43 | { |
44 | + logger.Trace("NavigateBookmarkView"); | |
45 | + | |
32 | 46 | this.rm.RequestNavigate( |
33 | 47 | IMainWindowViewModel.REGION_NAME, IBookmarkViewModel.URI); |
34 | 48 | } |
49 | + | |
50 | + public bool ContainsCategoryNo(int categoryNo) | |
51 | + { | |
52 | + return this.CategoryNoMap.ContainsKey(categoryNo); | |
53 | + } | |
54 | + | |
55 | + public void RegisterDetailList(int categoryNo, IBookmarkDetailListViewModel vm) | |
56 | + { | |
57 | + logger.Trace("RegisterDetailList: categoryNo {0}, vm {1}", categoryNo, vm.ToHashString()); | |
58 | + | |
59 | + this.CategoryNoMap.Add(categoryNo, vm); | |
60 | + } | |
61 | + | |
62 | + public void NavigateBookmarkListView(int categoryNo) | |
63 | + { | |
64 | + logger.Trace("NavigateBookmarkListView: categoryNo {0}", categoryNo); | |
65 | + | |
66 | + bool needsRefresh = !CategoryNoMap.ContainsKey(categoryNo); | |
67 | + | |
68 | + NavigationParameters args = new() | |
69 | + { | |
70 | + { IBookmarkDetailListViewModel.CATEGORY_NO_KEY, categoryNo } | |
71 | + }; | |
72 | + | |
73 | + this.rm.RequestNavigate( | |
74 | + IBookmarkViewModel.DETAIL_LIST_REGION_NAME, IBookmarkDetailListViewModel.URI, args); | |
75 | + | |
76 | + if (!needsRefresh) | |
77 | + { | |
78 | + return; | |
79 | + } | |
80 | + | |
81 | + NarouRefreshBookmarkDetailListRequest req = new(categoryNo); | |
82 | + | |
83 | + _ = Execute(req); | |
84 | + } | |
85 | + | |
86 | + public void SynchronizeBookmarkDetailList(int categoryNo, BookmarkDetailList detailList) | |
87 | + { | |
88 | + logger.Trace("SynchronizeBookmarkDetailList: categoryNo {0}", categoryNo); | |
89 | + | |
90 | + if (!CategoryNoMap.TryGetValue(categoryNo, out IBookmarkDetailListViewModel vm)) | |
91 | + { | |
92 | + return; | |
93 | + } | |
94 | + | |
95 | + vm.SynchronizeWith(detailList); | |
96 | + } | |
35 | 97 | } |
36 | 98 | } |
@@ -1,12 +1,15 @@ | ||
1 | 1 | using NLog; |
2 | 2 | using ObservableCollections; |
3 | 3 | using Prism.Navigation; |
4 | +using Prism.Regions; | |
4 | 5 | using Reactive.Bindings; |
5 | 6 | using Reactive.Bindings.Extensions; |
7 | +using System.Collections.Generic; | |
6 | 8 | using System.ComponentModel; |
7 | 9 | using System.Diagnostics; |
8 | 10 | using System.Reactive.Disposables; |
9 | 11 | using System.Windows.Data; |
12 | +using TestNarou.Adaptor.Boundary.Controller; | |
10 | 13 | using TestNarou.Adaptor.Boundary.Gateway.ViewModel; |
11 | 14 | using TestNarou.Adaptor.Boundary.Gateway.ViewModel.Child; |
12 | 15 | using TestNarou.Adaptor.Translator; |
@@ -16,13 +19,11 @@ using TestNarou.Domain.Model.Entity.Child; | ||
16 | 19 | namespace TestNarou.Adaptor.Gateway.ViewModel |
17 | 20 | { |
18 | 21 | internal class BookmarkDetailListViewModel |
19 | - : IBookmarkDetailListViewModel, INotifyPropertyChanged, IDestructible | |
22 | + : IBookmarkDetailListViewModel, INotifyPropertyChanged, INavigationAware, IDestructible | |
20 | 23 | { |
21 | 24 | private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); |
22 | 25 | |
23 | -#pragma warning disable CS0067 | |
24 | 26 | public event PropertyChangedEventHandler PropertyChanged; |
25 | -#pragma warning restore CS0067 | |
26 | 27 | |
27 | 28 | public ReactiveCommand CommandOpenBookmark { get; } |
28 | 29 |
@@ -30,16 +31,25 @@ namespace TestNarou.Adaptor.Gateway.ViewModel | ||
30 | 31 | |
31 | 32 | public ICollectionView Rows { get; private set; } = null; |
32 | 33 | |
34 | + private IAppWindowController WindowController { get; } | |
35 | + | |
36 | + private int CategoryNo { get; set; } = -1; | |
37 | + | |
33 | 38 | private ISynchronizedListView<BookmarkDetailListRow, IBookmarkDetailListRowViewModel> internalRows; |
34 | 39 | private IBookmarkDetailListRowViewModel selectedRow; |
35 | 40 | |
36 | 41 | private readonly IBookmarkDetailListRowViewModelTranslator vmTranslator; |
37 | 42 | private readonly CompositeDisposable disposables = new(); |
38 | 43 | |
39 | - public BookmarkDetailListViewModel(IBookmarkDetailListRowViewModelTranslator vmTranslator) | |
44 | + public BookmarkDetailListViewModel( | |
45 | + IAppWindowController wc, | |
46 | + IBookmarkDetailListRowViewModelTranslator vmTranslator) | |
40 | 47 | { |
48 | + this.WindowController = wc; | |
41 | 49 | this.vmTranslator = vmTranslator; |
42 | - this.CommandOpenBookmark = new ReactiveCommand().WithSubscribe(OpenBookmark).AddTo(disposables); | |
50 | + | |
51 | + this.CommandOpenBookmark = new ReactiveCommand() | |
52 | + .WithSubscribe(OpenBookmark).AddTo(disposables); | |
43 | 53 | } |
44 | 54 | |
45 | 55 | public void NotifySelectedItemChanged( |
@@ -90,5 +100,51 @@ namespace TestNarou.Adaptor.Gateway.ViewModel | ||
90 | 100 | { |
91 | 101 | this.disposables.Dispose(); |
92 | 102 | } |
103 | + | |
104 | + #region INavigationAware | |
105 | + | |
106 | + public bool IsNavigationTarget(NavigationContext ctx) | |
107 | + { | |
108 | + int categoryNo = GetCategoryNoFromNavigationContext(ctx); | |
109 | + | |
110 | + //logger.Trace("IsNavigationTarget: to:{0} <> this:{1}", categoryNo, this.CategoryNo); | |
111 | + | |
112 | + if (this.CategoryNo == -1 && !WindowController.ContainsCategoryNo(categoryNo)) | |
113 | + { | |
114 | + //logger.Trace("IsNavigationTarget: new Category"); | |
115 | + return true; | |
116 | + } | |
117 | + | |
118 | + bool isTarget = categoryNo == this.CategoryNo; | |
119 | + | |
120 | + //logger.Trace("IsNavigationTarget: isTarget {0}", isTarget); | |
121 | + | |
122 | + return isTarget; | |
123 | + } | |
124 | + | |
125 | + public void OnNavigatedTo(NavigationContext ctx) | |
126 | + { | |
127 | + int categoryNo = GetCategoryNoFromNavigationContext(ctx); | |
128 | + | |
129 | + //logger.Trace("OnNavigatedTo: to:{0} -> this:{1}", categoryNo, this.CategoryNo); | |
130 | + | |
131 | + if (this.CategoryNo == -1) | |
132 | + { | |
133 | + this.CategoryNo = categoryNo; | |
134 | + this.WindowController.RegisterDetailList(this.CategoryNo, this); | |
135 | + } | |
136 | + } | |
137 | + | |
138 | + public void OnNavigatedFrom(NavigationContext ctx) | |
139 | + { | |
140 | + // NOP | |
141 | + } | |
142 | + | |
143 | + private static int GetCategoryNoFromNavigationContext(NavigationContext ctx) | |
144 | + { | |
145 | + return ctx.Parameters.GetValue<int>(IBookmarkDetailListViewModel.CATEGORY_NO_KEY); | |
146 | + } | |
147 | + | |
148 | + #endregion | |
93 | 149 | } |
94 | 150 | } |
@@ -1,52 +1,24 @@ | ||
1 | -using NLog; | |
2 | -using Prism.Navigation; | |
3 | -using Prism.Regions; | |
1 | +using Prism.Navigation; | |
4 | 2 | using System.ComponentModel; |
5 | 3 | using System.Reactive.Disposables; |
6 | 4 | using TestNarou.Adaptor.Boundary.Gateway.ViewModel; |
7 | 5 | |
8 | 6 | namespace TestNarou.Adaptor.Gateway.ViewModel |
9 | 7 | { |
10 | - internal class BookmarkViewModel : INavigationAware, IBookmarkViewModel, IDestructible | |
8 | + internal class BookmarkViewModel : IBookmarkViewModel, IDestructible | |
11 | 9 | { |
12 | - private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); | |
10 | + //private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); | |
13 | 11 | |
14 | 12 | #pragma warning disable CS0067 |
15 | 13 | public event PropertyChangedEventHandler PropertyChanged; |
16 | 14 | #pragma warning restore CS0067 |
17 | 15 | |
18 | - private readonly IRegionManager rm; | |
19 | - | |
20 | 16 | private readonly CompositeDisposable disposables = new(); |
21 | 17 | |
22 | - public BookmarkViewModel(IRegionManager rm) | |
23 | - { | |
24 | - this.rm = rm; | |
25 | - } | |
26 | - | |
27 | 18 | public void Destroy() |
28 | 19 | { |
29 | 20 | this.disposables.Dispose(); |
30 | 21 | } |
31 | 22 | |
32 | - #region INavigationAware | |
33 | - | |
34 | - public bool IsNavigationTarget(NavigationContext ctx) | |
35 | - { | |
36 | - logger.Trace("BookmarkViewModel: IsNavigationTarget {0}", ctx.Uri); | |
37 | - | |
38 | - return true; | |
39 | - } | |
40 | - | |
41 | - public void OnNavigatedFrom(NavigationContext ctx) | |
42 | - { | |
43 | - // NOP | |
44 | - } | |
45 | - | |
46 | - public void OnNavigatedTo(NavigationContext ctx) | |
47 | - { | |
48 | - } | |
49 | - | |
50 | - #endregion | |
51 | 23 | } |
52 | 24 | } |
@@ -41,9 +41,7 @@ namespace TestNarou.Adaptor.Gateway.ViewModel.Child | ||
41 | 41 | return; |
42 | 42 | } |
43 | 43 | |
44 | - NarouRefreshBookmarkDetailListRequest req = new(this.Index); | |
45 | - | |
46 | - _ = this.Parent.WindowController.Execute(req); | |
44 | + this.Parent.WindowController.NavigateBookmarkListView(this.Index); | |
47 | 45 | } |
48 | 46 | |
49 | 47 | protected virtual void Dispose(bool disposing) |
@@ -56,16 +56,8 @@ namespace TestNarou.Adaptor.Gateway.ViewModel | ||
56 | 56 | return; |
57 | 57 | } |
58 | 58 | |
59 | - NarouRefreshBookmarkDetailListRequest req2 = new(1); | |
60 | - | |
61 | - var res2 = this.wc.Execute(req2); | |
62 | - | |
63 | - if (res2.IsAborted) | |
64 | - { | |
65 | - return; | |
66 | - } | |
67 | - | |
68 | 59 | this.wc.NavigateBookmarkView(); |
60 | + this.wc.NavigateBookmarkListView(1); | |
69 | 61 | } |
70 | 62 | |
71 | 63 | #endregion |
@@ -1,4 +1,5 @@ | ||
1 | -using TestNarou.Adaptor.Boundary.Gateway.ViewModel; | |
1 | +using TestNarou.Adaptor.Boundary.Controller; | |
2 | +using TestNarou.Adaptor.Boundary.Gateway.ViewModel; | |
2 | 3 | using TestNarou.UseCase.Boundary.Presenter; |
3 | 4 | using TestNarou.UseCase.Request; |
4 | 5 | using TestNarou.UseCase.Response; |
@@ -8,12 +9,13 @@ namespace TestNarou.Adaptor.Presenter | ||
8 | 9 | internal class NarouRefreshBookmarkDetailListPresenter |
9 | 10 | : INarouRefreshBookmarkDetailListPresenter |
10 | 11 | { |
11 | - private readonly IBookmarkDetailListViewModel vm; | |
12 | + private readonly IAppWindowController wc; | |
12 | 13 | |
13 | 14 | public NarouRefreshBookmarkDetailListPresenter( |
14 | - IBookmarkDetailListViewModel vm) | |
15 | + IAppWindowController wc | |
16 | + ) | |
15 | 17 | { |
16 | - this.vm = vm; | |
18 | + this.wc = wc; | |
17 | 19 | } |
18 | 20 | |
19 | 21 | public NarouRefreshBookmarkDetailListResponse Present( |
@@ -21,7 +23,7 @@ namespace TestNarou.Adaptor.Presenter | ||
21 | 23 | NarouRefreshBookmarkDetailListResponse res |
22 | 24 | ) |
23 | 25 | { |
24 | - this.vm.SynchronizeWith(res.DetailList); | |
26 | + this.wc.SynchronizeBookmarkDetailList(req.CategoryNo, res.DetailList); | |
25 | 27 | |
26 | 28 | return res; |
27 | 29 | } |
@@ -25,6 +25,8 @@ namespace TestNarou.OuterEdge | ||
25 | 25 | containerRegistry.RegisterForNavigation<LoginFormView>(); |
26 | 26 | containerRegistry.RegisterForNavigation<BookmarkView>(); |
27 | 27 | |
28 | + containerRegistry.RegisterForNavigation<BookmarkDetailListView>(); | |
29 | + | |
28 | 30 | /// |
29 | 31 | /// Repositories |
30 | 32 | /// |
@@ -74,8 +74,8 @@ namespace TestNarou.OuterEdge.Repository.API | ||
74 | 74 | |
75 | 75 | var response = await httpClient.SendAsync(request).ConfigureAwait(false); |
76 | 76 | |
77 | - ShowResponseHeaders(response); | |
78 | - ShowCookies(); | |
77 | + //ShowResponseHeaders(response); | |
78 | + //ShowCookies(); | |
79 | 79 | |
80 | 80 | logger.Trace("StatusCode: {0}", response.StatusCode); |
81 | 81 |
@@ -99,8 +99,8 @@ namespace TestNarou.OuterEdge.Repository.API | ||
99 | 99 | |
100 | 100 | var response = await httpClient.SendAsync(request).ConfigureAwait(false); |
101 | 101 | |
102 | - ShowResponseHeaders(response); | |
103 | - ShowCookies(); | |
102 | + //ShowResponseHeaders(response); | |
103 | + //ShowCookies(); | |
104 | 104 | |
105 | 105 | logger.Trace("StatusCode: {0}", response.StatusCode); |
106 | 106 |