Wrote a small helper class with extension methods to register the Nuclex.Avalonia MVVM services to a Microsoft.Extensions.DependencyInjection IoC container
This commit is contained in:
		
						commit
						708f87357e
					
				
					 4 changed files with 278 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net462;net8.0</TargetFrameworks>
 | 
			
		||||
    <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
 | 
			
		||||
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
 | 
			
		||||
    <GenerateDocumentationFile>True</GenerateDocumentationFile>
 | 
			
		||||
    <AssemblyName>Nuclex.Windows.Forms.DependencyInjection</AssemblyName>
 | 
			
		||||
    <RootNamespace>Nuclex.Windows.Forms.DependencyInjection</RootNamespace>
 | 
			
		||||
    <IntermediateOutputPath>obj\source</IntermediateOutputPath>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Remove="Tests\**" />
 | 
			
		||||
    <EmbeddedResource Remove="Tests\**" />
 | 
			
		||||
    <None Remove="Tests\**" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Remove=".git" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\Nuclex.Avalonia\Nuclex.Avalonia (netstandard-2.0).csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										48
									
								
								Properties/AssemblyInfo.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Properties/AssemblyInfo.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
#region Apache License 2.0
 | 
			
		||||
/*
 | 
			
		||||
Nuclex .NET Framework
 | 
			
		||||
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#endregion // Apache License 2.0
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
 | 
			
		||||
// General Information about an assembly is controlled through the following 
 | 
			
		||||
// set of attributes. Change these attribute values to modify the information
 | 
			
		||||
// associated with an assembly.
 | 
			
		||||
[assembly: AssemblyTitle("Nuclex.Avalonia.DependencyInjection")]
 | 
			
		||||
[assembly: AssemblyProduct("Nuclex.Avalonia.DependencyInjection")]
 | 
			
		||||
[assembly: AssemblyDescription("Add-on module to use Nuclex.Avalonia MVVM with Microsoft dependency injection interfaces")]
 | 
			
		||||
[assembly: AssemblyCompany("Nuclex Development Labs")]
 | 
			
		||||
[assembly: AssemblyCopyright("Copyright © Markus Ewald / Nuclex Development Labs 2002-2025")]
 | 
			
		||||
 | 
			
		||||
// Setting ComVisible to false makes the types in this assembly not visible 
 | 
			
		||||
// to COM components.  If you need to access a type in this assembly from 
 | 
			
		||||
// COM, set the ComVisible attribute to true on that type.
 | 
			
		||||
[assembly: ComVisible(false)]
 | 
			
		||||
 | 
			
		||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
 | 
			
		||||
[assembly: Guid("4b185e46-672f-4629-98e8-82db07aa8147")]
 | 
			
		||||
 | 
			
		||||
// Version information for an assembly consists of the following four values:
 | 
			
		||||
//
 | 
			
		||||
//      Major Version
 | 
			
		||||
//      Minor Version 
 | 
			
		||||
//      Build Number
 | 
			
		||||
//      Revision
 | 
			
		||||
//
 | 
			
		||||
[assembly: AssemblyVersion("1.3.0")]
 | 
			
		||||
							
								
								
									
										116
									
								
								Source/DependencyInjectedWindowManager.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								Source/DependencyInjectedWindowManager.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,116 @@
 | 
			
		|||
#region Apache License 2.0
 | 
			
		||||
/*
 | 
			
		||||
Nuclex .NET Framework
 | 
			
		||||
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#endregion // Apache License 2.0
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
#if NET6_0_OR_GREATER
 | 
			
		||||
using System.Runtime.Versioning;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
 | 
			
		||||
using Nuclex.Avalonia.AutoBinding;
 | 
			
		||||
 | 
			
		||||
namespace Nuclex.Avalonia.DependencyInjection {
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  ///   Window manager that is using Microsoft's dependency injection interfaces
 | 
			
		||||
  /// </summary>
 | 
			
		||||
#if NET6_0_OR_GREATER
 | 
			
		||||
  [SupportedOSPlatform("windows")]
 | 
			
		||||
#endif
 | 
			
		||||
  public class DependencyInjectedWindowManager : WindowManager {
 | 
			
		||||
 | 
			
		||||
    #region class WindowScope
 | 
			
		||||
 | 
			
		||||
    /// <summary>Manages a window-specific service scope</summary>
 | 
			
		||||
    private class WindowScope : IWindowScope, IDisposable {
 | 
			
		||||
 | 
			
		||||
      /// <summary>Initializes a new service scope for the window</summary>
 | 
			
		||||
      /// <param name="serviceProvider">
 | 
			
		||||
      ///   Service provider in which to create a scope
 | 
			
		||||
      /// </param>
 | 
			
		||||
      public WindowScope(IServiceProvider serviceProvider) {
 | 
			
		||||
        this.serviceScope = serviceProvider.CreateScope();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /// <summary>Creates an instance of the specified type in the scope</summary>
 | 
			
		||||
      /// <param name="type">Type an instance will be created of</param>
 | 
			
		||||
      /// <returns>The created instance</returns>
 | 
			
		||||
      /// <remarks>
 | 
			
		||||
      ///   Use this to wire up your dependency injection container. By default,
 | 
			
		||||
      ///   the Activator class will be used to create instances which only works
 | 
			
		||||
      ///   if all of your view models are concrete classes.
 | 
			
		||||
      /// </remarks>
 | 
			
		||||
      public object CreateInstance(Type type) {
 | 
			
		||||
        return this.serviceScope.ServiceProvider.GetRequiredService(type);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /// <summary>Immediately destroys all services owned by the scope</summary>
 | 
			
		||||
      public void Dispose() {
 | 
			
		||||
        if(this.serviceScope != null) {
 | 
			
		||||
          this.serviceScope.Dispose();
 | 
			
		||||
          this.serviceScope = null;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /// <summary>Service scope that will be used to create instances</summary>
 | 
			
		||||
      private IServiceScope serviceScope;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion // class WindowScope
 | 
			
		||||
 | 
			
		||||
    /// <summary>Initializes a new window manager</summary>
 | 
			
		||||
    ///	<param name="serviceProvider">
 | 
			
		||||
    ///	  Dependency injector the window manager uses to construct view models
 | 
			
		||||
    ///	</param>
 | 
			
		||||
    /// <param name="autoBinder">
 | 
			
		||||
    ///   View model binder that will be used to bind all created views to their models
 | 
			
		||||
    /// </param>
 | 
			
		||||
    public DependencyInjectedWindowManager(
 | 
			
		||||
      IServiceProvider serviceProvider, IAutoBinder autoBinder = null
 | 
			
		||||
    ) :
 | 
			
		||||
      base(autoBinder) {
 | 
			
		||||
      this.serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>Creates an instance of the specified type</summary>
 | 
			
		||||
    /// <param name="type">Type an instance will be created of</param>
 | 
			
		||||
    /// <returns>The created instance</returns>
 | 
			
		||||
    /// <remarks>
 | 
			
		||||
    ///   Use this to wire up your dependency injection container. By default,
 | 
			
		||||
    ///   the Activator class will be used to create instances which only works
 | 
			
		||||
    ///   if all of your view models are concrete classes.
 | 
			
		||||
    /// </remarks>
 | 
			
		||||
    protected override object CreateInstance(Type type) {
 | 
			
		||||
      return this.serviceProvider.GetRequiredService(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>Creates a new scope in which window-specific services will live</summary>
 | 
			
		||||
    /// <returns>The new scope managing the lifetime of window-specific services</returns>
 | 
			
		||||
    protected override IWindowScope CreateWindowScope() {
 | 
			
		||||
      return new WindowScope(this.serviceProvider);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>The service provider used to create new instances</summary>
 | 
			
		||||
    private readonly IServiceProvider serviceProvider;
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
} // namespace Nuclex.Avalonia.DependencyInjection
 | 
			
		||||
							
								
								
									
										83
									
								
								Source/MvvmExtensions.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								Source/MvvmExtensions.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,83 @@
 | 
			
		|||
#region Apache License 2.0
 | 
			
		||||
/*
 | 
			
		||||
Nuclex .NET Framework
 | 
			
		||||
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#endregion // Apache License 2.0
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
 | 
			
		||||
using Nuclex.Avalonia.AutoBinding;
 | 
			
		||||
using Nuclex.Avalonia.Messages;
 | 
			
		||||
 | 
			
		||||
namespace Nuclex.Avalonia.DependencyInjection {
 | 
			
		||||
 | 
			
		||||
  /// <summary>Sets up the service bindings for an MVVM-based application</summary>
 | 
			
		||||
  public static class MvvmExtensions {
 | 
			
		||||
 | 
			
		||||
    /// <summary>Registers all MVVM supporting services for a WinForms application</summary>
 | 
			
		||||
    /// <param name="services">Service collection the services will be registered to</param>
 | 
			
		||||
    /// <returns>The service collection for method chaining</returns>
 | 
			
		||||
    public static IServiceCollection AddMvvm(this IServiceCollection services) {
 | 
			
		||||
 | 
			
		||||
      // Allow displaying message boxes via the AvaloniaMessagePresenter which wraps
 | 
			
		||||
      // the MessageBox.Avalonia library
 | 
			
		||||
      services.AddSingleton<IMessageService, AvaloniaMessagePresenter>();
 | 
			
		||||
 | 
			
		||||
      // The window manager keeps track of which Window is in the foreground
 | 
			
		||||
      // and handles opening modal or modeless windows for which it either
 | 
			
		||||
      // binds provided view models or requests new instances.
 | 
			
		||||
      services.AddSingleton<WindowManager, DependencyInjectedWindowManager>();
 | 
			
		||||
 | 
			
		||||
      // The IWindowManager is the main interface that should be used to
 | 
			
		||||
      // create new windows and dialogs
 | 
			
		||||
      services.AddSingleton<IWindowManager>(
 | 
			
		||||
        sp => sp.GetRequiredService<WindowManager>()
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // The IActiveWindowTracker is a very simple interface to let Windows Forms
 | 
			
		||||
      // extensions that need to display message boxes or other things query for
 | 
			
		||||
      // the currently active top-level window.
 | 
			
		||||
      services.AddSingleton<IActiveWindowTracker>(
 | 
			
		||||
        sp => sp.GetRequiredService<WindowManager>()
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // The auto binder uses convention-over-configuration to automatically
 | 
			
		||||
      // establish data bindings or call view model methods that share their name
 | 
			
		||||
      // with button controls.
 | 
			
		||||
      services.AddSingleton<IAutoBinder, ConventionBinder>();
 | 
			
		||||
 | 
			
		||||
      return services;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>Registers all MVVM supporting services for a WinForms application</summary>
 | 
			
		||||
    /// <param name="services">Service collection the services will be registered to</param>
 | 
			
		||||
    /// <returns>The service collection for method chaining</returns>
 | 
			
		||||
    public static IServiceCollection AddCommonDialogs(this IServiceCollection services) {
 | 
			
		||||
 | 
			
		||||
      // Implementation of the message service that uses plain MessageBoxes
 | 
			
		||||
      // from the Win32 API to display messages to the user
 | 
			
		||||
      services.AddSingleton<IMessageService, AvaloniaMessagePresenter>();
 | 
			
		||||
 | 
			
		||||
      return services;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
} // namespace Nuclex.Avalonia.DependencyInjection
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue