Pegged latest versions of all involved projects; split single NuGet package recipe into three, one core and one each for Ninject and Microsoft dependency injection

This commit is contained in:
Markus Ewald 2025-06-19 18:32:22 +02:00
parent b7627e0126
commit 0c2f0f787f
12 changed files with 184 additions and 47 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
NuclexSupportConfig.cmake FoundationPackageConfig.cmake
third-party
# Visual Studio Codium # Visual Studio Codium
.vscode/* .vscode/*

5
.gitmodules vendored
View File

@ -13,3 +13,8 @@
url = ../../nuclex-shared-dotnet/Nuclex.Windows.Forms.Ninject.git url = ../../nuclex-shared-dotnet/Nuclex.Windows.Forms.Ninject.git
branch = main branch = main
update = rebase update = rebase
[submodule "Nuclex.Windows.Forms.DependencyInjection"]
path = Nuclex.Windows.Forms.DependencyInjection
url = ../../nuclex-shared-dotnet/Nuclex.Windows.Forms.DependencyInjection.git
branch = main
update = rebase

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Nuclex.Foundation.DependencyInjection</id>
<version>1.2.0</version>
<title>Dependency injection bindings for the Nuclex Foundation Libraries</title>
<authors>Markus Ewald</authors>
<owners></owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">Apache-2.0</license>
<readme>ReadMe.md</readme>
<projectUrl>https://github.com/orgs/nuclex-shared-dotnet/repositories</projectUrl>
<description>Bindings to use Microsoft's (and compatible) dependency injector in Microsoft.Extensions.DependencyInjection(.Asbtraction) for view models with Nuclex.Windows.Forms</description>
<language>en-US</language>
<tags>mvvm,util,ninject,dependency-injection</tags>
<icon>nuclex-logo.png</icon>
<repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Windows.Forms.DependencyInjection.git" commit="573b7ab93d25034a649bdf401f5439ec15c165f5" />
<dependencies>
<group targetFramework=".NETFramework4.6.2">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Microsoft.Extensions.DependencyInjection.Asbtraction" version="[8.0.0, 10.0.0)" exclude="Build,Analyzers" />
</group>
<group targetFramework="net8.0-windows7.0">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Microsoft.Extensions.DependencyInjection.Asbtraction" version="[8.0.0, 10.0.0)" exclude="Build,Analyzers" />
</group>
</dependencies>
<frameworkReferences>
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net8.0-windows7.0">
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
</group>
</frameworkReferences>
</metadata>
<files>
<file src="ReadMe.md" target="ReadMe.md" />
<file src="nuclex-logo.png" target="nuclex-logo.png" />
<!-- Feature set for .NET Framework 4.6.2 (with Windows.Forms) -->
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net462\Nuclex.Windows.Forms.DependencyInjection.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net462\Nuclex.Windows.Forms.DependencyInjection.xml" target="lib/net462" />
<!-- Feature set for .NET 8.0 on Windows (with Windows.Forms) -->
<!-- Btw, '-windows7.0' means Windows Seven, the one between Vista and 8, not the internal Windows release number -->
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.DependencyInjection.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.DependencyInjection.xml" target="lib/net8.0-windows7.0" />
</files>
</package>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Nuclex.Foundation.Ninject</id>
<version>1.2.0</version>
<title>Ninject bindings for the Nuclex Foundation Libraries</title>
<authors>Markus Ewald</authors>
<owners></owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">Apache-2.0</license>
<readme>ReadMe.md</readme>
<projectUrl>https://github.com/orgs/nuclex-shared-dotnet/repositories</projectUrl>
<description>Bindings to use Ninject for dependency injection in view model with Nuclex.Windows.Forms</description>
<language>en-US</language>
<tags>mvvm,util,ninject,dependency-injection</tags>
<icon>nuclex-logo.png</icon>
<repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Windows.Forms.Ninject.git" commit="66a7848d1f149160726fda055051dd7ca7afa312" />
<dependencies>
<group targetFramework=".NETFramework4.6.2">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" />
</group>
<group targetFramework="net8.0-windows7.0">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" />
</group>
</dependencies>
<frameworkReferences>
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net8.0-windows7.0">
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
</group>
</frameworkReferences>
</metadata>
<files>
<file src="ReadMe.md" target="ReadMe.md" />
<file src="nuclex-logo.png" target="nuclex-logo.png" />
<!-- Feature set for .NET Framework 4.6.2 (with Windows.Forms) -->
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.xml" target="lib/net462" />
<!-- Feature set for .NET 8.0 on Windows (with Windows.Forms) -->
<!-- Btw, '-windows7.0' means Windows Seven, the one between Vista and 8, not the internal Windows release number -->
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.Ninject.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.Ninject.xml" target="lib/net8.0-windows7.0" />
</files>
</package>

View File

@ -2,31 +2,29 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>Nuclex.Foundation</id> <id>Nuclex.Foundation</id>
<version>1.1.0</version> <version>1.2.0</version>
<title>Nuclex Foundation Libraries</title> <title>Nuclex Foundation Libraries</title>
<authors>Markus Ewald</authors> <authors>Markus Ewald</authors>
<owners></owners> <owners></owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">Apache-2.0</license> <license type="expression">Apache-2.0</license>
<licenseUrl>https://licenses.nuget.org/Apache-2.0</licenseUrl>
<readme>ReadMe.md</readme> <readme>ReadMe.md</readme>
<projectUrl>https://github.com/nuclex-shared-dotnet/Nuclex.Support</projectUrl> <projectUrl>https://github.com/orgs/nuclex-shared-dotnet/repositories</projectUrl>
<description>Set of basic libraries offering tools for MVVM-based UIs, storage of settings, license keys, collections and observer/subscriber pattern helpers</description> <description>Set of basic libraries offering tools for MVVM-based UIs, storage of settings, license keys, collections and observer/subscriber pattern helpers</description>
<language>en-US</language> <language>en-US</language>
<tags>mvvm,util</tags> <tags>mvvm,util</tags>
<icon>nuclex-logo.png</icon> <icon>nuclex-logo.png</icon>
<repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Support.git" commit="a59facff90816bb3d7d53761ffea43c0102e6047" /> <repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Support.git" commit="5fb433ad983e58725e0d25faa8968a75b3dfd178" />
<dependencies> <dependencies>
<group targetFramework=".NETStandard2.0" /> <group targetFramework=".NETStandard2.0" />
<group targetFramework=".NETFramework4.6.2"> <group targetFramework=".NETFramework4.6.2" />
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" /> <group targetFramework="net8.0-windows7.0" />
</group>
<group targetFramework="net6.0-windows7.0">
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" />
</group>
</dependencies> </dependencies>
<frameworkReferences> <frameworkReferences>
<group targetFramework=".NETStandard2.0" />
<group targetFramework=".NETFramework4.6.2" /> <group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net6.0-windows7.0"> <group targetFramework="net8.0-windows7.0">
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" /> <frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
</group> </group>
</frameworkReferences> </frameworkReferences>
@ -45,17 +43,13 @@
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.xml" target="lib/net462" /> <file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.xml" target="lib/net462" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net462\Nuclex.Windows.Forms.dll" target="lib/net462" /> <file src="Nuclex.Windows.Forms\bin\$Configuration$\net462\Nuclex.Windows.Forms.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net462\Nuclex.Windows.Forms.xml" target="lib/net462" /> <file src="Nuclex.Windows.Forms\bin\$Configuration$\net462\Nuclex.Windows.Forms.xml" target="lib/net462" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.xml" target="lib/net462" />
<!-- Featue set for .NET Framework 4.6.2 (with Windows.Forms) --> <!-- Feature set for .NET 8.0 on Windows (with Windows.Forms) -->
<!-- Btw, '-windows7'.0 means Windows Seven, the one between Vista and 8, not the internal Windows relaese number --> <!-- Btw, '-windows7.0' means Windows Seven, the one between Vista and 8, not the internal Windows release number -->
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.dll" target="lib/net6.0-windows7.0" /> <file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.xml" target="lib/net6.0-windows7.0" /> <file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.xml" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.dll" target="lib/net6.0-windows7.0" /> <file src="Nuclex.Windows.Forms\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.xml" target="lib/net6.0-windows7.0" /> <file src="Nuclex.Windows.Forms\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.xml" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.Ninject.dll" target="lib/net6.0-windows7.0" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.Ninject.xml" target="lib/net6.0-windows7.0" />
</files> </files>
</package> </package>

@ -1 +1 @@
Subproject commit e818fae81012b0a819abcf2180b90eee1d998fb7 Subproject commit 5fb433ad983e58725e0d25faa8968a75b3dfd178

@ -1 +1 @@
Subproject commit 563d45f9f2f3b666586eb0862088ac3e00566389 Subproject commit d057f704497b63faa5e57c6330afb436a0d9708c

@ -0,0 +1 @@
Subproject commit 573b7ab93d25034a649bdf401f5439ec15c165f5

@ -1 +1 @@
Subproject commit cb4e39895666e467dec8b3b92abdd73127687385 Subproject commit d3e1a3e24e7ff6615996ec9236495b6d1275de5c

View File

@ -35,7 +35,7 @@ void saveSettingsToIni() {
var iniStore = new ConfigurationFileStore(); var iniStore = new ConfigurationFileStore();
saveSettings(iniStore); saveSettings(iniStore);
using(var writer = new StreamWriteR("awesome-app.ini")) { using(var writer = new StreamWriter("awesome-app.ini")) {
iniStore.Save(writer); iniStore.Save(writer);
writer.Flush() writer.Flush()
} }
@ -78,9 +78,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>());
}
} }
``` ```
@ -99,8 +98,8 @@ will be assigned to its `DataContext` property, establishing
the View/ViewModel relationship. the View/ViewModel relationship.
Adding an IoC Container (Ninject) to the MVVM Example Adding Dependency Injection to the MVVM Example
----------------------------------------------------- -----------------------------------------------
In the previous example, the view and its view model were constructed using In the previous example, the view and its view model were constructed using
`Activator.CreateInstance()` - a method provided by .NET that creates a new `Activator.CreateInstance()` - a method provided by .NET that creates a new
@ -111,30 +110,55 @@ to provide the ViewModel with the data it is supposed to be an adapter for.
You can achieve that by constructing the ViewModel yourself and passing it You can achieve that by constructing the ViewModel yourself and passing it
to the `WindowManager.OpenRoot()` or `WindowManager.ShowModal()` methods. to the `WindowManager.OpenRoot()` or `WindowManager.ShowModal()` methods.
A much better approach is to use a dependency injector - an IoC container with A much better approach is to use a dependency injector that automatically
automatic constructor parameter injection. My favorite one is Ninject (due to wires up your view models to app-internal services, repositories and managers
its neat setup with a fluent interface), but you can use any container you to which the view models and mediate.
wish, simply by inheriting your own `WindowManager` class:
Let's do the full program with the host application builder from Microsoft's
`Microsoft.Extensions.Hosting` assembly which would also give you logging and
hosted services in addition its dependency injector:
```csharp ```csharp
public class NinjectWindowManager : WindowManager { [STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
public NinjectWindowManager(IKernel kernel, IAutoBinder autoBinder = null) : HostApplicationBuilder builder = Host.CreateApplicationBuilder(
base(autoBinder) { new HostApplicationBuilderSettings() {
this.kernel = kernel; DisableDefaults = true,
ContentRootPath = "",
ApplicationName = "Example"
}
);
// These are extension methods in Nuclex.Windows.Forms.DependencyInjection
builder.Services.AddMvvm(); // Window Manager
builder.Services.AddCommonDialogs(); // Message boxes, file dialogs, etc.
// View models and dialogs must be explicitly registered by default.
// This requirement can be relaxed.
builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<MainForm>();
// Create the host (in which all application services and scopes will
// be managed) and run the main window.
using(IHost host = builder.Build()) {
var windowManager = host.Services.GetRequiredService<IWindowManager>();
Application.Run(windowManager.OpenRoot<MainViewModel>());
} }
protected override object CreateInstance(Type type) {
return this.kernel.Get(type);
}
private IKernel kernel;
} }
``` ```
Your `NinjectWindowManager` will now use `IKernel.Get()` to construct its Now view models can access any registered services. By default, each view and
ViewModels, allowing their constructors to require any services and instances view model pair lives inside of an implicit 'scope', meaning that services
you have set up in your Ninject kernel. added via `builder.Services.AddScoped<T>()` will have unique instances per open
dialog or window.
This is very useful if your dialogs perform background processing via threads
(i.e. using `ThreadedViewModel`) or tasks where a shared database connection,
for example, would lead to trouble when it is asked to run another query while
a data reader is still open.
```csharp ```csharp
class MainViewModel { class MainViewModel {

View File

@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nuclex.Windows.Forms.Ninjec
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unit Tests", "Unit Tests", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unit Tests", "Unit Tests", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nuclex.Windows.Forms.DependencyInjection (net-4.6)(net-8.0)", "Nuclex.Windows.Forms.DependencyInjection\Nuclex.Windows.Forms.DependencyInjection (net-4.6)(net-8.0).csproj", "{3D7D6CA0-A130-FD54-B772-B4B48847E682}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -41,6 +43,10 @@ Global
{98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Release|Any CPU.Build.0 = Release|Any CPU {98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Release|Any CPU.Build.0 = Release|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

5
nuget-pack.cmd Normal file
View File

@ -0,0 +1,5 @@
@ECHO OFF
nuget pack Nuclex.Foundation.nuspec -Version 1.2.0 -Properties Configuration=Release
nuget pack Nuclex.Foundation.Ninject.nuspec -Version 1.2.0 -Properties Configuration=Release
nuget pack Nuclex.Foundation.DependencyInjection.nuspec -Version 1.2.0 -Properties Configuration=Release