DataContext change event was not triggered on .NET 8.0 because it brings its own DataContext property and related event, adapted the code to still fire my custom OnDataContextChange() notification

This commit is contained in:
Markus Ewald 2025-06-24 11:12:34 +02:00
parent d057f70449
commit 7376852ae1
4 changed files with 56 additions and 25 deletions

View File

@ -140,7 +140,7 @@ namespace Nuclex.Windows.Forms.Views {
/// <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
/// This is supposed to be overridden 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.

View File

@ -85,12 +85,23 @@ namespace Nuclex.Windows.Forms.Views {
}
}
}
#else
/// <summary>Called when the control's data context has changed</summary>
/// <param name="arguments">Not used</param>
protected override void OnDataContextChanged(EventArgs arguments) {
object oldDataContext = this.dataContext;
this.dataContext = base.DataContext;
if(this.dataContext != oldDataContext) {
OnDataContextChanged(this, oldDataContext, this.dataContext);
}
}
#endif
#if !NET8_0_OR_GREATER
// NOTE: Careful! On .NET 8.0, the Control class has its own DataContext,
// but this one will be used to be able to report the previous one.
/// <summary>Active data binding target, can be null</summary>
private object dataContext;
#endif
/// <summary>Delegate for the OnViewModelPropertyChanged() method</summary>
private PropertyChangedEventHandler onViewModelPropertyChangedDelegate;

View File

@ -42,20 +42,6 @@ namespace Nuclex.Windows.Forms.Views {
this.onViewModelPropertyChangedDelegate = OnViewModelPropertyChanged;
}
#if !NET8_0_OR_GREATER
/// <summary>Provides the data binding target for the view</summary>
public object DataContext {
get { return this.dataContext; }
set {
if(value != this.dataContext) {
object oldDataContext = this.dataContext;
this.dataContext = value;
OnDataContextChanged(this, oldDataContext, value);
}
}
}
#endif
/// <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>
@ -88,9 +74,34 @@ namespace Nuclex.Windows.Forms.Views {
) { }
#if !NET8_0_OR_GREATER
/// <summary>Provides the data binding target for the view</summary>
public object DataContext {
get { return this.dataContext; }
set {
if(value != this.dataContext) {
object oldDataContext = this.dataContext;
this.dataContext = value;
OnDataContextChanged(this, oldDataContext, value);
}
}
}
#else
/// <summary>Called when the control's data context has changed</summary>
/// <param name="arguments">Not used</param>
protected override void OnDataContextChanged(EventArgs arguments) {
object oldDataContext = this.dataContext;
this.dataContext = base.DataContext;
if(this.dataContext != oldDataContext) {
OnDataContextChanged(this, oldDataContext, this.dataContext);
}
}
#endif
// NOTE: Careful! On .NET 8.0, the Control class has its own DataContext,
// but this one will be used to be able to report the previous one.
/// <summary>Active data binding target, can be null</summary>
private object dataContext;
#endif
/// <summary>Delegate for the OnViewModelPropertyChanged() method</summary>
private PropertyChangedEventHandler onViewModelPropertyChangedDelegate;

View File

@ -363,14 +363,20 @@ namespace Nuclex.Windows.Forms {
return Activator.CreateInstance(type);
}
/// <summary>Creates an instance of the specified type in a new scope</summary>
/// <param name="type">Type an instance will be created of</param>
/// <returns>The created instance and the scope in which it lives</returns>
/// <summary>Creates a new scope in which window-specific instances live</summary>
/// <returns>
/// A new scope in which scoped services requested by the window's view model
/// will live
/// </returns>
/// <remarks>
/// This is identical to <see cref="CreateInstance" /> but, if used together
/// with a dependency injector, should also create a service scope. This way,
/// an implicit service scope will cover the lifetime of a view model and
/// any non-singleton services will use new instances, avoiding, for example,
/// If you do not override this method, services will be constructed through
/// the normal <see cref="CreateInstance" /> method (which actually may not
/// work without managing your own service scope in case your dependency
/// injector supports scopes and some of your services are scoped). By
/// overriding this method, you can automatically cause a new scope to be
/// created for each window or dialog. That way, an implicit service scope
/// will cover the lifetime of each window and its view model and any
/// non-singleton services will use new instances, avoiding, for example,
/// that multiple dialogs access the same database connection simultaneously.
/// </remarks>
protected virtual IWindowScope CreateWindowScope() {
@ -464,6 +470,9 @@ namespace Nuclex.Windows.Forms {
/// <param name="control">
/// Control that will dispose a scope when it is itself disposed
/// </param>
/// <param name="scope">
/// Scope that will be disposed together with the control
/// </param>
private void setupScopeDisposal(Control control, IWindowScope scope) {
if(!ReferenceEquals(scope, this.windowManagerAsScope)) {
IDisposable disposableScope = scope as IDisposable;