The progress spinner can now tell its optimal size required to show the entire status text but overlap as few controls as possible; began implementing a generic version of a multi page view model and matching view with caching
git-svn-id: file:///srv/devel/repo-conversion/nuwi@53 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
17ec2d0f69
commit
91432c5209
|
@ -82,6 +82,7 @@
|
||||||
<Compile Include="Source\ViewModels\DialogViewModel.Test.cs">
|
<Compile Include="Source\ViewModels\DialogViewModel.Test.cs">
|
||||||
<DependentUpon>DialogViewModel.cs</DependentUpon>
|
<DependentUpon>DialogViewModel.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\ViewModels\IMultiPageViewModel.cs" />
|
||||||
<Compile Include="Source\ViewModels\MultiPageViewModel.cs" />
|
<Compile Include="Source\ViewModels\MultiPageViewModel.cs" />
|
||||||
<Compile Include="Source\ViewModels\ThreadedAction.cs" />
|
<Compile Include="Source\ViewModels\ThreadedAction.cs" />
|
||||||
<Compile Include="Source\ViewModels\ThreadedAction.Test.cs">
|
<Compile Include="Source\ViewModels\ThreadedAction.Test.cs">
|
||||||
|
@ -98,6 +99,9 @@
|
||||||
<Compile Include="Source\IActiveWindowTracker.cs" />
|
<Compile Include="Source\IActiveWindowTracker.cs" />
|
||||||
<Compile Include="Source\Views\IView.cs" />
|
<Compile Include="Source\Views\IView.cs" />
|
||||||
<Compile Include="Source\IWindowManager.cs" />
|
<Compile Include="Source\IWindowManager.cs" />
|
||||||
|
<Compile Include="Source\Views\MultiPageViewForm.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Source\Views\ViewControl.cs">
|
<Compile Include="Source\Views\ViewControl.cs">
|
||||||
<SubType>UserControl</SubType>
|
<SubType>UserControl</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -94,6 +94,29 @@ namespace Nuclex.Windows.Forms.Controls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Calculates the optimal size for the spinner control</summary>
|
||||||
|
/// <returns>The optimal size for the spinner control to have</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// Thanks to WinForms limited control transparency, the progress spinner needs to
|
||||||
|
/// redraw every control behind it each time it updates. Thus it's wise to keep it
|
||||||
|
/// as small as possible, but wide enough to fit the status text, if any.
|
||||||
|
/// </remarks>
|
||||||
|
public Size GetOptimalSize() {
|
||||||
|
SizeF textRectangle;
|
||||||
|
using(var dummyImage = new Bitmap(1, 1)) {
|
||||||
|
using(Graphics graphics = Graphics.FromImage(dummyImage)) {
|
||||||
|
textRectangle = graphics.MeasureString(
|
||||||
|
this.statusText, this.statusFont
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Size(
|
||||||
|
Math.Max(128, (int)(textRectangle.Width + 2.0f)),
|
||||||
|
this.statusFont.Height + 128
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Font that is used to display the status text</summary>
|
/// <summary>Font that is used to display the status text</summary>
|
||||||
public Font StatusFont {
|
public Font StatusFont {
|
||||||
get { return this.statusFont; }
|
get { return this.statusFont; }
|
||||||
|
|
14
Source/ViewModels/IMultiPageViewModel.cs
Normal file
14
Source/ViewModels/IMultiPageViewModel.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Nuclex.Windows.Forms.ViewModels {
|
||||||
|
|
||||||
|
/// <summary>Interface for vew models that can switch between different pages</summary>
|
||||||
|
public interface IMultiPageViewModel {
|
||||||
|
|
||||||
|
/// <summary>Retrieves (and, if needed, creates) the view model for the active page</summary>
|
||||||
|
/// <returns>A view model for the active page on the multi-page view model</returns>
|
||||||
|
object GetActivePageViewModel();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Windows.Forms.ViewModels
|
|
@ -19,6 +19,7 @@ License along with this library
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
using Nuclex.Support;
|
using Nuclex.Support;
|
||||||
|
|
||||||
|
@ -26,8 +27,8 @@ namespace Nuclex.Windows.Forms.ViewModels {
|
||||||
|
|
||||||
/// <summary>Base class for view models that have multiple child view models</summary>
|
/// <summary>Base class for view models that have multiple child view models</summary>
|
||||||
/// <typeparam name="TPageEnumeration">Enum type by which pages can be indicated</typeparam>
|
/// <typeparam name="TPageEnumeration">Enum type by which pages can be indicated</typeparam>
|
||||||
public abstract class MultiPageViewModel<TPageEnumeration> : Observable
|
public abstract class MultiPageViewModel<TPageEnumeration> :
|
||||||
where TPageEnumeration : IEquatable<TPageEnumeration> {
|
Observable, IMultiPageViewModel, IDisposable {
|
||||||
|
|
||||||
/// <summary>Initializes a new multi-page view model</summary>
|
/// <summary>Initializes a new multi-page view model</summary>
|
||||||
/// <param name="windowManager">
|
/// <param name="windowManager">
|
||||||
|
@ -38,6 +39,25 @@ namespace Nuclex.Windows.Forms.ViewModels {
|
||||||
/// </param>
|
/// </param>
|
||||||
public MultiPageViewModel(IWindowManager windowManager, bool cachePageViewModels = false) {
|
public MultiPageViewModel(IWindowManager windowManager, bool cachePageViewModels = false) {
|
||||||
this.windowManager = windowManager;
|
this.windowManager = windowManager;
|
||||||
|
if(cachePageViewModels) {
|
||||||
|
this.cachedViewModels = new ConcurrentDictionary<TPageEnumeration, object>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Immediately releases all resources owned by the instance</summary>
|
||||||
|
public virtual void Dispose() {
|
||||||
|
if(this.cachedViewModels != null) {
|
||||||
|
foreach(object cacheViewModel in this.cachedViewModels.Values) {
|
||||||
|
disposeIfSupported(cacheViewModel);
|
||||||
|
}
|
||||||
|
this.activePageViewModel = null;
|
||||||
|
|
||||||
|
this.cachedViewModels.Clear();
|
||||||
|
this.cachedViewModels = null;
|
||||||
|
} else if(this.activePageViewModel != null) {
|
||||||
|
disposeIfSupported(this.activePageViewModel);
|
||||||
|
this.activePageViewModel = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Child page that is currently being displayed by the view model</summary>
|
/// <summary>Child page that is currently being displayed by the view model</summary>
|
||||||
|
@ -46,11 +66,36 @@ namespace Nuclex.Windows.Forms.ViewModels {
|
||||||
set {
|
set {
|
||||||
if(!this.activePage.Equals(value)) {
|
if(!this.activePage.Equals(value)) {
|
||||||
this.activePage = value;
|
this.activePage = value;
|
||||||
|
if(this.activePageViewModel != null) {
|
||||||
|
if(this.cachedViewModels == null) {
|
||||||
|
disposeIfSupported(this.activePageViewModel);
|
||||||
|
}
|
||||||
|
this.activePageViewModel = null;
|
||||||
|
}
|
||||||
OnPropertyChanged(nameof(ActivePage));
|
OnPropertyChanged(nameof(ActivePage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Retrieves (and, if needed, creates) the view model for the active page</summary>
|
||||||
|
/// <returns>A view model for the active page on the multi-page view model</returns>
|
||||||
|
public object GetActivePageViewModel() {
|
||||||
|
if(this.cachedViewModels == null) {
|
||||||
|
if(this.activePageViewModel == null) {
|
||||||
|
this.activePageViewModel = CreateViewModelForPage(this.activePage);
|
||||||
|
}
|
||||||
|
} else if(this.activePageViewModel == null) {
|
||||||
|
this.activePageViewModel = this.cachedViewModels.GetOrAdd(
|
||||||
|
this.activePage,
|
||||||
|
delegate(TPageEnumeration activePage) {
|
||||||
|
return CreateViewModelForPage(this.activePage);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.activePageViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Windowmanager that can create view models and display other views</summary>
|
/// <summary>Windowmanager that can create view models and display other views</summary>
|
||||||
protected IWindowManager WindowManager {
|
protected IWindowManager WindowManager {
|
||||||
get { return this.windowManager; }
|
get { return this.windowManager; }
|
||||||
|
@ -59,13 +104,27 @@ namespace Nuclex.Windows.Forms.ViewModels {
|
||||||
/// <summary>Creates a view model for the specified page</summary>
|
/// <summary>Creates a view model for the specified page</summary>
|
||||||
/// <param name="page">Page for which a view model will be created</param>
|
/// <param name="page">Page for which a view model will be created</param>
|
||||||
/// <returns>The view model for the specified page</returns>
|
/// <returns>The view model for the specified page</returns>
|
||||||
protected abstract object createViewModelForPage(TPageEnumeration page);
|
protected abstract object CreateViewModelForPage(TPageEnumeration page);
|
||||||
|
|
||||||
|
/// <summary>Disposes the specified object if it is disposable</summary>
|
||||||
|
/// <param name="potentiallyDisposable">Object that will be disposed if supported</param>
|
||||||
|
private static void disposeIfSupported(object potentiallyDisposable) {
|
||||||
|
var disposable = potentiallyDisposable as IDisposable;
|
||||||
|
if(disposable != null) {
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Page that is currently active in the multi-page view model</summary>
|
/// <summary>Page that is currently active in the multi-page view model</summary>
|
||||||
private TPageEnumeration activePage;
|
private TPageEnumeration activePage;
|
||||||
/// <summary>Window manager that can be used to display other views</summary>
|
/// <summary>Window manager that can be used to display other views</summary>
|
||||||
private IWindowManager windowManager;
|
private IWindowManager windowManager;
|
||||||
|
|
||||||
|
/// <summary>View model for the active page</summary>
|
||||||
|
private object activePageViewModel;
|
||||||
|
/// <summary>Cached page view models, if caching is enabled</summary>
|
||||||
|
private ConcurrentDictionary<TPageEnumeration, object> cachedViewModels;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Windows.Forms.ViewModels
|
} // namespace Nuclex.Windows.Forms.ViewModels
|
||||||
|
|
287
Source/Views/MultiPageViewForm.cs
Normal file
287
Source/Views/MultiPageViewForm.cs
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using Nuclex.Support;
|
||||||
|
using Nuclex.Windows.Forms.ViewModels;
|
||||||
|
|
||||||
|
namespace Nuclex.Windows.Forms.Views {
|
||||||
|
|
||||||
|
/// <summary>Special view form that can display different child views</summary>
|
||||||
|
public class MultiPageViewForm : ViewForm {
|
||||||
|
|
||||||
|
/// <summary>Initializes a new multi page view window</summary>
|
||||||
|
/// <param name="windowManager">
|
||||||
|
/// Window manager that is used to set up the child views
|
||||||
|
/// </param>
|
||||||
|
/// <param name="cachePageViews">Whether page views should be kept alive and reused</param>
|
||||||
|
public MultiPageViewForm(IWindowManager windowManager, bool cachePageViews = false) {
|
||||||
|
this.windowManager = windowManager;
|
||||||
|
this.createViewMethod = typeof(IWindowManager).GetMethod("CreateView");
|
||||||
|
|
||||||
|
if(cachePageViews) {
|
||||||
|
this.cachedViews = new Dictionary<Type, Control>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Called when the control is being disposed</summary>
|
||||||
|
/// <param name="calledExplicitly">
|
||||||
|
/// Whether the call was made by user code (vs. the garbage collector)
|
||||||
|
/// </param>
|
||||||
|
protected override void Dispose(bool calledExplicitly) {
|
||||||
|
if(calledExplicitly) {
|
||||||
|
|
||||||
|
// Disable the active view, if any
|
||||||
|
if(this.activePageView != null) {
|
||||||
|
if(this.childViewContainer != null) {
|
||||||
|
this.childViewContainer.Controls.Remove(this.activePageView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If caching is disabled, dispose of the active child view, if any
|
||||||
|
if(this.cachedViews == null) {
|
||||||
|
if(this.activePageView != null) {
|
||||||
|
disposeIfSupported(this.activePageView);
|
||||||
|
this.activePageView = null;
|
||||||
|
}
|
||||||
|
} else { // Caching is enabled, dispose of any cached child views
|
||||||
|
foreach(Control childView in this.cachedViews.Values) {
|
||||||
|
disposeIfSupported(childView);
|
||||||
|
}
|
||||||
|
this.cachedViews.Clear();
|
||||||
|
this.cachedViews = null;
|
||||||
|
this.activePageView = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(calledExplicitly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Discovers the container control used to host the child views</summary>
|
||||||
|
/// <returns>The container control is which the child views will be hosted</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is supposed to be overriden by the user, simply returning the container
|
||||||
|
/// control that should host the page views. If it isn't, however, we use some
|
||||||
|
/// heuristics to figure out the most likely candidate: it should be a container,
|
||||||
|
/// and it should cover most of the window's client area.
|
||||||
|
/// </remarks>
|
||||||
|
protected virtual Control IdentifyPageContainer() {
|
||||||
|
Size halfWindowSize = Size;
|
||||||
|
halfWindowSize.Width /= 2;
|
||||||
|
halfWindowSize.Height /= 2;
|
||||||
|
|
||||||
|
// First container control we found -- if we find no likely candidate,
|
||||||
|
// we simply use the first
|
||||||
|
Control firstContainer = null;
|
||||||
|
|
||||||
|
// Check all top-level controls in the window. If there's a container that
|
||||||
|
// covers most of the window, it's our best bet
|
||||||
|
int controlCount = Controls.Count;
|
||||||
|
for(int index = 0; index < controlCount; ++index) {
|
||||||
|
Control control = Controls[index];
|
||||||
|
|
||||||
|
// Only check container controls
|
||||||
|
if((control is ContainerControl) || (control is Panel)) {
|
||||||
|
if(firstContainer == null) {
|
||||||
|
firstContainer = control;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this control covers most of the view, it's our candidate!
|
||||||
|
Size controlSize = control.Size;
|
||||||
|
bool goodCandidate = (
|
||||||
|
(controlSize.Width > halfWindowSize.Width) &&
|
||||||
|
(controlSize.Height > halfWindowSize.Height)
|
||||||
|
);
|
||||||
|
if(goodCandidate) {
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no candidate was found, return the first container control we encountered
|
||||||
|
// or create a new UserControl as the container if nothing was found at all.
|
||||||
|
if(firstContainer == null) {
|
||||||
|
firstContainer = new Panel();
|
||||||
|
Controls.Add(firstContainer);
|
||||||
|
firstContainer.Dock = DockStyle.Fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Called when the window's data context is changed</summary>
|
||||||
|
/// <param name="sender">Window whose data context was changed</param>
|
||||||
|
/// <param name="oldDataContext">Data context that was previously used</param>
|
||||||
|
/// <param name="newDataContext">Data context that will be used from now on</param>
|
||||||
|
protected override void OnDataContextChanged(
|
||||||
|
object sender, object oldDataContext, object newDataContext
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Kill the currently active view if there was an old view model.
|
||||||
|
if(oldDataContext != null) {
|
||||||
|
disableActivePageView();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnDataContextChanged(sender, oldDataContext, newDataContext);
|
||||||
|
|
||||||
|
// If a valid view model was assigned, create a new view its active page view model
|
||||||
|
if(newDataContext != null) {
|
||||||
|
var dataContextAsMultiPageViewModel = newDataContext as IMultiPageViewModel;
|
||||||
|
if(dataContextAsMultiPageViewModel != null) {
|
||||||
|
activatePageView(dataContextAsMultiPageViewModel.GetActivePageViewModel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Called when a property of the view model is changed</summary>
|
||||||
|
/// <param name="sender">View model in which a property was changed</param>
|
||||||
|
/// <param name="arguments">Contains the name of the property that has changed</param>
|
||||||
|
protected override void OnViewModelPropertyChanged(
|
||||||
|
object sender, PropertyChangedEventArgs arguments
|
||||||
|
) {
|
||||||
|
base.OnViewModelPropertyChanged(sender, arguments);
|
||||||
|
|
||||||
|
MultiPageViewModel<bool> anyMultiPageViewModel;
|
||||||
|
if(arguments.AreAffecting(nameof(anyMultiPageViewModel.ActivePage))) {
|
||||||
|
var viewModelAsMultiPageviewModel = DataContext as IMultiPageViewModel;
|
||||||
|
if(viewModelAsMultiPageviewModel != null) {
|
||||||
|
activatePageView(viewModelAsMultiPageviewModel.GetActivePageViewModel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Activates the page view for the specified page view model</summary>
|
||||||
|
/// <param name="pageViewModel">
|
||||||
|
/// Page view model for which the page view will be activated
|
||||||
|
/// </param>
|
||||||
|
private void activatePageView(object pageViewModel) {
|
||||||
|
object activePageViewModel = null;
|
||||||
|
{
|
||||||
|
var activePageViewAsView = this.activePageView as IView;
|
||||||
|
if(activePageViewAsView != null) {
|
||||||
|
activePageViewModel = activePageViewAsView.DataContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try from the cheapest to the most expensive way to get to our goal,
|
||||||
|
// an activated view suiting the specified view model.
|
||||||
|
|
||||||
|
// If we already have the target view model selected, do nothing
|
||||||
|
if(activePageViewModel == pageViewModel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the page view model for the old and the new page are of the same
|
||||||
|
// type, we can reuse the currently active page view
|
||||||
|
if((activePageViewModel != null) && (pageViewModel != null)) {
|
||||||
|
if(pageViewModel.GetType() == this.activePageView.GetType()) {
|
||||||
|
var activePageViewAsView = this.activePageView as IView;
|
||||||
|
if(activePageViewAsView != null) {
|
||||||
|
activePageViewAsView.DataContext = pageViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Worst, but usual, case: the new page view model might require
|
||||||
|
// a different view. Create or look up the new view and put it in the container
|
||||||
|
{
|
||||||
|
disableActivePageView();
|
||||||
|
|
||||||
|
this.activePageView = getOrCreatePageView(pageViewModel);
|
||||||
|
|
||||||
|
Control pageViewContainer = getPageViewContainer();
|
||||||
|
pageViewContainer.Controls.Add(this.activePageView);
|
||||||
|
this.activePageView.Dock = DockStyle.Fill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the cached child view or creates a new one if not cached</summary>
|
||||||
|
/// <param name="viewModel">View model for which a child view will be returned</param>
|
||||||
|
/// <returns>A child view suitable for the specified view model</returns>
|
||||||
|
private Control getOrCreatePageView(object viewModel) {
|
||||||
|
Type viewModelType = viewModel.GetType();
|
||||||
|
|
||||||
|
Control view;
|
||||||
|
|
||||||
|
// If caching is enabled, check if we have a cached view
|
||||||
|
if(this.cachedViews != null) {
|
||||||
|
if(this.cachedViews.TryGetValue(viewModelType, out view)) {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, call the window manager's CreateView() method
|
||||||
|
MethodInfo specializedCreateViewMethod = (
|
||||||
|
this.createViewMethod.MakeGenericMethod(viewModelType)
|
||||||
|
);
|
||||||
|
view = (Control)specializedCreateViewMethod.Invoke(
|
||||||
|
this.windowManager, new object[1] { viewModel }
|
||||||
|
);
|
||||||
|
|
||||||
|
// If caching is enabled, register the view in the cache
|
||||||
|
if(this.cachedViews != null) {
|
||||||
|
this.cachedViews.Add(viewModelType, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Disables the currently active page view control</summary>
|
||||||
|
private void disableActivePageView() {
|
||||||
|
if(this.activePageView != null) {
|
||||||
|
Control container = getPageViewContainer();
|
||||||
|
container.Controls.Remove(this.activePageView);
|
||||||
|
|
||||||
|
// If we don't reuse views, kill it now
|
||||||
|
if(this.cachedViews == null) {
|
||||||
|
disposeIfSupported(this.activePageView);
|
||||||
|
this.activePageView = null;
|
||||||
|
} else {
|
||||||
|
var activePageViewAsView = this.activePageView as IView;
|
||||||
|
if(activePageViewAsView != null) {
|
||||||
|
activePageViewAsView.DataContext = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Fetches the container that holds the child views</summary>
|
||||||
|
/// <returns>The container for the child views</returns>
|
||||||
|
private Control getPageViewContainer() {
|
||||||
|
if(this.childViewContainer == null) {
|
||||||
|
this.childViewContainer = IdentifyPageContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.childViewContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Disposes the specified object if it is disposable</summary>
|
||||||
|
/// <param name="potentiallyDisposable">Object that will be disposed if supported</param>
|
||||||
|
private static void disposeIfSupported(object potentiallyDisposable) {
|
||||||
|
var disposable = potentiallyDisposable as IDisposable;
|
||||||
|
if(disposable != null) {
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Window manager through which the child views are created</summary>
|
||||||
|
private IWindowManager windowManager;
|
||||||
|
/// <summary>Reflection info for the createView() method of the window manager</summary>
|
||||||
|
private MethodInfo createViewMethod;
|
||||||
|
|
||||||
|
/// <summary>Container in which the child views will be hosted</summary>
|
||||||
|
private Control childViewContainer;
|
||||||
|
/// <summary>Cached views that will be reused when the view model activates them</summary>
|
||||||
|
private Dictionary<Type, Control> cachedViews;
|
||||||
|
/// <summary>The currently active child view</summary>
|
||||||
|
private Control activePageView;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Windows.Forms.Views
|
Loading…
Reference in New Issue
Block a user