Dreamine.MVVM.Wpf 1.0.3
Dreamine.MVVM.Wpf 사용자 인터페이스 기능과 구성 요소를 제공합니다.
로딩중...
검색중...
일치하는것 없음
ViewManager.cs
이 파일의 문서화 페이지로 가기
1using Dreamine.MVVM.Core;
2using Dreamine.MVVM.Interfaces.DependencyInjection;
3using Dreamine.MVVM.Interfaces.Navigation;
4using Dreamine.MVVM.Interfaces.Windows;
5using Dreamine.MVVM.Locators;
6using System;
7using System.Collections.Generic;
8using System.Diagnostics;
9using System.Windows;
10using System.Windows.Controls;
11
12namespace Dreamine.MVVM.Wpf
13{
22 public sealed class ViewManager : IViewManager
23 {
32 private readonly IServiceResolver _resolver;
41 private readonly List<IViewDisplayStrategy> _customStrategies = new();
50 private readonly double _fallbackWindowWidth;
59 private readonly double _fallbackWindowHeight;
60
101 public ViewManager(IServiceResolver resolver, double fallbackWindowWidth = 800, double fallbackWindowHeight = 600)
102 {
103 _resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
104 _fallbackWindowWidth = fallbackWindowWidth > 0 ? fallbackWindowWidth : 800;
105 _fallbackWindowHeight = fallbackWindowHeight > 0 ? fallbackWindowHeight : 600;
106 }
107
116 public ViewManager() : this(DMContainer.GetResolver())
117 {
118 }
119
136 public void RegisterDisplayStrategy(IViewDisplayStrategy strategy)
137 {
138 ArgumentNullException.ThrowIfNull(strategy);
139 _customStrategies.Add(strategy);
140 }
141
158 public void Show<TViewModel>() where TViewModel : class
159 {
160 Show(typeof(TViewModel));
161 }
162
179 public void Show(Type viewModelType)
180 {
181 ArgumentNullException.ThrowIfNull(viewModelType);
182
183 object viewModel = _resolver.Resolve(viewModelType);
184 object? view = ViewModelLocator.ResolveView(viewModelType);
185 DisplayResolvedView(view, viewModel, viewModelType, useRegionNavigator: true);
186 }
187
204 public void Navigate(object viewModel)
205 {
206 ArgumentNullException.ThrowIfNull(viewModel);
207
208 Type viewModelType = viewModel.GetType();
209 object? view = ViewModelLocator.ResolveView(viewModelType);
210 DisplayResolvedView(view, viewModel, viewModelType, useRegionNavigator: false);
211 }
212
254 object? view,
255 object viewModel,
256 Type viewModelType,
257 bool useRegionNavigator)
258 {
259 if (view is null)
260 {
261 Debug.WriteLine(
262 $"[ViewManager] No view found for {viewModelType.FullName}. " +
263 "Ensure the view is registered via ViewModelLocator.Register<TView, TViewModel>().");
264 return;
265 }
266
267 // Custom strategies take precedence — checked before built-in WPF types.
268 foreach (var strategy in _customStrategies)
269 {
270 if (strategy.CanHandle(view))
271 {
272 strategy.Display(view, viewModel, viewModelType, useRegionNavigator);
273 return;
274 }
275 }
276
277 // Built-in WPF type handling.
278 switch (view)
279 {
280 case Window window:
281 ShowWindow(window, viewModel, viewModelType);
282 break;
283
284 case UserControl userControl:
285 ShowUserControl(userControl, viewModel, useRegionNavigator);
286 break;
287
288 case Page page:
289 ShowPage(page, viewModel, useRegionNavigator);
290 break;
291
292 default:
293 Debug.WriteLine(
294 $"[ViewManager] No display strategy found for view type {view.GetType().FullName}. " +
295 "Register a custom IViewDisplayStrategy via RegisterDisplayStrategy().");
296 break;
297 }
298 }
299
332 private void ShowWindow(Window window, object viewModel, Type viewModelType)
333 {
334 string windowKey = GetViewKey(viewModelType);
335 IWindowStateService? windowStateService = TryResolve<IWindowStateService>();
336
337 if (windowStateService?.IsOpen(windowKey) == true)
338 {
339 ActivateExistingWindow(windowKey);
340 return;
341 }
342
343 window.DataContext = viewModel;
344
345 // 메인 윈도우를 Owner로 지정합니다.
346 // WPF는 Owner가 닫힐 때 소유된 모든 창을 자동으로 닫아주므로
347 // 메인 창 종료 시 팝업이 남아있는 문제를 방지합니다.
348 var mainWindow = Application.Current?.MainWindow;
349 if (mainWindow is not null && mainWindow != window && mainWindow.IsLoaded)
350 {
351 window.Owner = mainWindow;
352 }
353
354 windowStateService?.MarkOpened(windowKey);
355
356 window.Closed += (_, _) =>
357 {
358 windowStateService?.MarkClosed(windowKey);
359 };
360
361 window.Show();
362 }
363
396 private void ShowUserControl(UserControl userControl, object viewModel, bool useRegionNavigator)
397 {
398 userControl.DataContext = viewModel;
399
400 INavigator? navigator = useRegionNavigator ? TryResolve<INavigator>() : null;
401 if (navigator is not null && navigator is not ViewManager)
402 {
403 navigator.Navigate(viewModel);
404 return;
405 }
406
407 new Window
408 {
409 Content = userControl,
410 Width = _fallbackWindowWidth,
411 Height = _fallbackWindowHeight
412 }.Show();
413 }
414
447 private void ShowPage(Page page, object viewModel, bool useRegionNavigator)
448 {
449 page.DataContext = viewModel;
450
451 INavigator? navigator = useRegionNavigator ? TryResolve<INavigator>() : null;
452 if (navigator is not null && navigator is not ViewManager)
453 {
454 navigator.Navigate(viewModel);
455 return;
456 }
457
458 new Window
459 {
460 Content = page,
461 Width = _fallbackWindowWidth,
462 Height = _fallbackWindowHeight
463 }.Show();
464 }
465
482 private static void ActivateExistingWindow(string windowKey)
483 {
484 foreach (Window window in Application.Current.Windows)
485 {
486 if (GetViewKey(window.GetType()) == windowKey)
487 {
488 window.Activate();
489 return;
490 }
491
492 if (window.DataContext is not null &&
493 GetViewKey(window.DataContext.GetType()) == windowKey)
494 {
495 window.Activate();
496 return;
497 }
498 }
499 }
500
525 private static string GetViewKey(Type type)
526 {
527 string name = type.Name;
528
529 if (name.EndsWith("ViewModel", StringComparison.Ordinal))
530 return name[..^"ViewModel".Length];
531
532 if (name.EndsWith("Window", StringComparison.Ordinal))
533 return name[..^"Window".Length];
534
535 if (name.EndsWith("View", StringComparison.Ordinal))
536 return name[..^"View".Length];
537
538 if (name.EndsWith("Page", StringComparison.Ordinal))
539 return name[..^"Page".Length];
540
541 return name;
542 }
543
568 private T? TryResolve<T>() where T : class
569 {
570 _resolver.TryResolve<T>(out var result);
571 return result;
572 }
573 }
574}
ViewManager(IServiceResolver resolver, double fallbackWindowWidth=800, double fallbackWindowHeight=600)
readonly double _fallbackWindowHeight
void Show(Type viewModelType)
static void ActivateExistingWindow(string windowKey)
void ShowWindow(Window window, object viewModel, Type viewModelType)
readonly IServiceResolver _resolver
void ShowUserControl(UserControl userControl, object viewModel, bool useRegionNavigator)
void RegisterDisplayStrategy(IViewDisplayStrategy strategy)
void ShowPage(Page page, object viewModel, bool useRegionNavigator)
readonly double _fallbackWindowWidth
void DisplayResolvedView(object? view, object viewModel, Type viewModelType, bool useRegionNavigator)
void Navigate(object viewModel)
readonly List< IViewDisplayStrategy > _customStrategies
static string GetViewKey(Type type)