View model disposal is now done via a lambda method with captured variables rather than by tagging the view
This commit is contained in:
parent
07be49c952
commit
f6457b1909
@ -57,9 +57,8 @@ static void Main() {
|
|||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
|
||||||
using(var windowManager = new WindowManager()) {
|
var windowManager = new WindowManager();
|
||||||
Application.Run(windowManager.OpenRoot<MainViewModel>());
|
Application.Run(windowManager.OpenRoot<MainViewModel>());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -21,6 +21,10 @@ using System;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
#endif
|
||||||
|
|
||||||
using Nuclex.Support;
|
using Nuclex.Support;
|
||||||
|
|
||||||
namespace Nuclex.Windows.Forms.Views {
|
namespace Nuclex.Windows.Forms.Views {
|
||||||
@ -28,6 +32,9 @@ namespace Nuclex.Windows.Forms.Views {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for MVVM user controls that act as views connected to a view model
|
/// Base class for MVVM user controls that act as views connected to a view model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
#endif
|
||||||
public class ViewControl : UserControl, IView {
|
public class ViewControl : UserControl, IView {
|
||||||
|
|
||||||
/// <summary>Initializes a new view control</summary>
|
/// <summary>Initializes a new view control</summary>
|
||||||
|
@ -29,6 +29,7 @@ using System.Runtime.Versioning;
|
|||||||
using Nuclex.Support;
|
using Nuclex.Support;
|
||||||
using Nuclex.Windows.Forms.AutoBinding;
|
using Nuclex.Windows.Forms.AutoBinding;
|
||||||
using Nuclex.Windows.Forms.Views;
|
using Nuclex.Windows.Forms.Views;
|
||||||
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
||||||
|
|
||||||
namespace Nuclex.Windows.Forms {
|
namespace Nuclex.Windows.Forms {
|
||||||
|
|
||||||
@ -125,11 +126,10 @@ namespace Nuclex.Windows.Forms {
|
|||||||
window.Closed += this.rootWindowClosedDelegate;
|
window.Closed += this.rootWindowClosedDelegate;
|
||||||
|
|
||||||
// If we either created the view model or the user explicitly asked us to
|
// If we either created the view model or the user explicitly asked us to
|
||||||
// dispose his view model, tag the window so that we know to dispose it
|
// dispose his view model, prepare the window so that it will dispose its
|
||||||
// when we're done (but still allow the user to change his mind)
|
// view model when the window is done.
|
||||||
if((viewModel == null) || disposeOnClose) {
|
if((viewModel == null) || disposeOnClose) {
|
||||||
window.Tag = "DisposeViewModelOnClose"; // TODO: Wrap SetProp() instead?
|
setupViewModelDisposal(window);
|
||||||
//window.SetValue(DisposeViewModelOnCloseProperty, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.Show();
|
window.Show();
|
||||||
@ -158,11 +158,10 @@ namespace Nuclex.Windows.Forms {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// If we either created the view model or the user explicitly asked us to
|
// If we either created the view model or the user explicitly asked us to
|
||||||
// dispose his view model, tag the window so that we know to dispose it
|
// dispose his view model, prepare the window so that it will dispose its
|
||||||
// when we're done (but still allow the user to change his mind)
|
// view model when the window is done.
|
||||||
if((viewModel == null) || disposeOnClose) {
|
if((viewModel == null) || disposeOnClose) {
|
||||||
window.Tag = "DisposeViewModelOnClose"; // TODO: Wrap SetProp() instead?
|
setupViewModelDisposal(window);
|
||||||
//window.SetValue(DisposeViewModelOnCloseProperty, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogResult result = window.ShowDialog(this.activeWindow);
|
DialogResult result = window.ShowDialog(this.activeWindow);
|
||||||
@ -178,14 +177,6 @@ namespace Nuclex.Windows.Forms {
|
|||||||
window.Activated -= this.rootWindowActivatedDelegate;
|
window.Activated -= this.rootWindowActivatedDelegate;
|
||||||
ActiveWindow = window.Owner;
|
ActiveWindow = window.Owner;
|
||||||
|
|
||||||
if(shouldDisposeViewModelOnClose(window)) {
|
|
||||||
IView windowAsView = window as IView;
|
|
||||||
if(windowAsView != null) {
|
|
||||||
object viewModelAsObject = windowAsView.DataContext;
|
|
||||||
windowAsView.DataContext = null;
|
|
||||||
disposeIfDisposable(viewModelAsObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
disposeIfDisposable(window);
|
disposeIfDisposable(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,6 +322,10 @@ namespace Nuclex.Windows.Forms {
|
|||||||
return Activator.CreateInstance(type);
|
return Activator.CreateInstance(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual object CreateServiceScope() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Called when one of the application's root windows is closed</summary>
|
/// <summary>Called when one of the application's root windows is closed</summary>
|
||||||
/// <param name="sender">Window that has been closed</param>
|
/// <param name="sender">Window that has been closed</param>
|
||||||
/// <param name="arguments">Not used</param>
|
/// <param name="arguments">Not used</param>
|
||||||
@ -339,20 +334,11 @@ namespace Nuclex.Windows.Forms {
|
|||||||
closedWindow.Closed -= this.rootWindowClosedDelegate;
|
closedWindow.Closed -= this.rootWindowClosedDelegate;
|
||||||
closedWindow.Activated -= this.rootWindowActivatedDelegate;
|
closedWindow.Activated -= this.rootWindowActivatedDelegate;
|
||||||
|
|
||||||
// If the view model was created just for this view or if the user asked us
|
|
||||||
// to dispose of his view model, do so now.
|
|
||||||
if(shouldDisposeViewModelOnClose(closedWindow)) {
|
|
||||||
IView windowAsView = closedWindow as IView;
|
|
||||||
if(windowAsView != null) {
|
|
||||||
object viewModelAsObject = windowAsView.DataContext;
|
|
||||||
windowAsView.DataContext = null;
|
|
||||||
disposeIfDisposable(viewModelAsObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lock(this) {
|
lock(this) {
|
||||||
ActiveWindow = null;
|
ActiveWindow = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//disposeIfDisposable(closedWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Called when one of the application's root windows is activated</summary>
|
/// <summary>Called when one of the application's root windows is activated</summary>
|
||||||
@ -402,16 +388,24 @@ namespace Nuclex.Windows.Forms {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Determines if the view owns the view model</summary>
|
/// <summary>Attaches a view model disposer to a control</summary>
|
||||||
/// <param name="view">View that will be checked for ownership</param>
|
/// <param name="control">
|
||||||
/// <returns>True if the view owns the view model</returns>
|
/// Control whose view model will be disposed when it is itself disposed
|
||||||
private static bool shouldDisposeViewModelOnClose(Control view) {
|
/// </param>
|
||||||
string tagAsString = view.Tag as string;
|
private void setupViewModelDisposal(Control control) {
|
||||||
if(tagAsString != null) {
|
IView controlAsView = control as IView;
|
||||||
return tagAsString.Contains("DisposeViewModelOnClose");
|
if(controlAsView != null) {
|
||||||
} else {
|
IDisposable disposableViewModel = controlAsView.DataContext as IDisposable;
|
||||||
return false;
|
if(disposableViewModel != null) {
|
||||||
|
control.Disposed += delegate(object sender, EventArgs arguments) {
|
||||||
|
disposableViewModel.Dispose();
|
||||||
|
controlAsView.DataContext = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//window.Tag = "DisposeViewModelOnClose"; // TODO: Wrap SetProp() instead?
|
||||||
|
//window.SetValue(DisposeViewModelOnCloseProperty, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Filters a list of types to contain only those in a specific namespace</summary>
|
/// <summary>Filters a list of types to contain only those in a specific namespace</summary>
|
||||||
|
Loading…
Reference in New Issue
Block a user