41 Commits

Author SHA1 Message Date
amacocian c8c783aaed Fix pipelines 2026-01-06 16:46:57 +01:00
amacocian fc6cb11880 Update to .net 10 2026-01-06 16:26:06 +01:00
amacocian 4b3002b164 Remove gitlab mirror 2025-09-13 13:45:16 +02:00
amacocian 8dd9d93e2b Migrate to slnx 2025-09-12 11:45:30 +02:00
amacocian ca9e682d04 Expose CoreWebView2 initialization logic 2025-08-03 11:12:36 +02:00
amacocian 103ee09b0e Setup custom window chrome 2025-08-02 00:33:26 +02:00
amacocian ce5e5e780a Shader compiler fixes 2025-08-01 16:31:06 +02:00
amacocian 0c85e6a8d9 Restructure project 2025-08-01 16:15:41 +02:00
amacocian 8121d3191e Move shared files to shared folder 2025-08-01 15:38:48 +02:00
amacocian 786728d632 Fix tests 2025-08-01 15:22:43 +02:00
amacocian a2afb3b1ee Update dotnet version in pipelines 2025-08-01 15:18:15 +02:00
amacocian f02af67c7f Setup WpfExtended.Blazor extensions 2025-08-01 15:15:47 +02:00
amacocian ffe46f1e37 Slim upgrades and bugfixes 2025-07-30 12:35:42 +02:00
amacocian 187cd6609d Update Slim 2025-07-30 01:05:06 +02:00
amacocian c22ec7d874 Update dependency 2025-07-30 00:23:22 +02:00
amacocian 32560f7326 Update dependencies 2025-07-29 19:11:33 +02:00
amacocian dc6907bc79 Make ApplicationStarting asynchronous 2025-05-14 12:45:14 +02:00
amacocian c0f4b69d80 Fix tests 2025-05-14 12:18:38 +02:00
amacocian 8ac8b78758 Add switch for showing main window on startup 2025-05-14 12:08:14 +02:00
amacocian 9d7ce59e14 Use compilation units
Use filescoped namespaces where supported
2024-04-11 11:59:00 +02:00
amacocian 5d63d73f93 Fix pipelines 2024-04-10 21:52:13 +02:00
amacocian e6df17358b Switch to Incremental Generators
Implement INotifyPropertyChanged Generator
2024-04-10 21:48:51 +02:00
amacocian a4dbcd9d53 Change snowfall noise algorithm 2023-10-31 17:47:53 +01:00
amacocian 16f60dbc57 Remove wind direction. Use instead WindStrength 2023-10-30 18:24:43 +01:00
amacocian 3206512cfb Adjust snowfall noise 2023-10-30 11:41:57 +01:00
amacocian b666bd7968 Snowfall effect 2023-10-30 00:18:52 +01:00
amacocian 02f83fc78e DepthBlur, Noise, Impasto effects 2023-09-11 10:10:29 +02:00
amacocian da2263c30f Update .net in pipelines 2023-08-31 23:50:43 +02:00
amacocian faf7e4248b Fix DependencyPropertySourceGenerator broken due to unknown diagnostic message (#17) 2023-08-31 23:47:31 +02:00
amacocian daca000745 Remove Moq 2023-08-09 19:11:44 +02:00
amacocian 409b6cdf16 Fix initialization order (#15) 2023-05-02 20:39:06 +02:00
amacocian 13d5a0f7f6 Bump dependencies (#14) 2022-09-12 19:43:15 +02:00
amacocian 64da5aa909 Update WpfExtended.csproj (#13) 2022-09-12 12:31:05 +02:00
amacocian 544ec77667 Integrate with Microsoft.Extensions.DependencyInjection (#12)
* Integrate with Microsoft.Extensions.DependencyInjection

* Setup CODEOWNERS
2022-09-09 20:13:59 +02:00
amacocian d349041cbe Update dependencies (#11)
* Update dependencies

* Fix pipelines
2022-08-03 22:42:19 +02:00
amacocian 40e85ffe96 Update dependencies (#10) 2021-09-10 10:10:12 +02:00
amacocian dd99b05ee8 Update DI nuget (#8) 2021-07-10 13:18:46 +03:00
amacocian 1325a6821e Move DI code to SystemExtensions nuget (#7) 2021-07-10 11:43:53 +03:00
Alexandru Macocian cd68132463 Update Slim dependency 2021-06-17 13:06:45 +02:00
amacocian 7e9c3c5f64 Create unit tests (#6)
* Create unit tests
Rearrange test project structure
Implement ICVLoggerProvider interface for mocking/extensibility

* Fix UTs project path
2021-06-16 15:09:49 +02:00
amacocian f818f4152d Application lifetime interface (#5)
Application lifetime hooks for services
Options implementations and resolver
Options manager interface to manage options
2021-06-11 13:34:23 +02:00
75 changed files with 1708 additions and 1655 deletions
+1
View File
@@ -0,0 +1 @@
* amacocian@yahoo.com
+15 -14
View File
@@ -17,9 +17,7 @@ jobs:
env:
Configuration: Release
Solution_Path: WpfExtended.sln
Test_Project_Path: Slim.Tests\Slim.Tests.csproj
Source_Project_Path: Slim\Slim.csproj
Solution_Path: WpfExtended.slnx
Actions_Allow_Unsecure_Commands: true
steps:
@@ -31,7 +29,7 @@ jobs:
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.202'
dotnet-version: '10.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -44,17 +42,20 @@ jobs:
- name: Build WpfExtended project
run: dotnet build WpfExtended -c $env:Configuration -p:SolutionDir=$env:GITHUB_WORKSPACE
- name: Push WpfExtended Nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: WpfExtended\WpfExtended.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Package WpfExtended
run: dotnet pack -c Release -o . WpfExtended\WpfExtended.csproj
- name: Build WpfExtended.SourceGeneration project
run: dotnet build WpfExtended.SourceGeneration -c $env:Configuration
- name: Push WpfExtended.SourceGeneration Nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: WpfExtended.SourceGeneration\WpfExtended.SourceGeneration.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Package WpfExtended.SourceGeneration
run: dotnet pack -c Release -o . WpfExtended.SourceGeneration\WpfExtended.SourceGeneration.csproj
- name: Build WpfExtended.Blazor project
run: dotnet build WpfExtended.Blazor -c $env:Configuration
- name: Package WpfExtended.Blazor
run: dotnet pack -c Release -o . WpfExtended.Blazor\WpfExtended.Blazor.csproj
- name: Publish
run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
+3 -2
View File
@@ -19,8 +19,9 @@ jobs:
runs-on: windows-latest
env:
Solution_Path: WpfExtended.sln
Solution_Path: WpfExtended.slnx
Actions_Allow_Unsecure_Commands: true
Test_Project_Path: WpfExtended.Test\WpfExtended.Tests.csproj
steps:
- name: Checkout
@@ -31,7 +32,7 @@ jobs:
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.202'
dotnet-version: '10.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -0,0 +1,9 @@
using Microsoft.Web.WebView2.Core;
using System;
namespace WpfExtended.Blazor.Exceptions;
public sealed class CoreWebView2Exception(CoreWebView2ProcessFailedEventArgs args, string message, Exception? innerException = default) : Exception(message, innerException)
{
public CoreWebView2ProcessFailedEventArgs Args { get; } = args ?? throw new ArgumentNullException(nameof(args));
}
@@ -0,0 +1,26 @@
<Window
x:Class="WpfExtended.Blazor.Launch.BlazorHostWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:blazor="clr-namespace:Microsoft.AspNetCore.Components.WebView.Wpf;assembly=Microsoft.AspNetCore.Components.WebView.Wpf"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfExtended.Blazor.Launch"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
x:Name="_this"
Title="BlazorHostWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<shell:WindowChrome.WindowChrome>
<WindowChrome x:Name="WindowChrome" />
</shell:WindowChrome.WindowChrome>
<blazor:BlazorWebView
x:Name="BlazorWebView"
HostPage="{Binding ElementName=_this, Path=HostPage, Mode=OneWay}"
Services="{Binding ElementName=_this, Path=Services, Mode=OneWay}">
<blazor:BlazorWebView.RootComponents>
<blazor:RootComponent x:Name="RootComponent" Selector="#app" />
</blazor:BlazorWebView.RootComponents>
</blazor:BlazorWebView>
</Window>
@@ -0,0 +1,121 @@
using Microsoft.AspNetCore.Components.WebView;
using Microsoft.AspNetCore.Components.WebView.Wpf;
using Microsoft.Web.WebView2.Core;
using System;
using System.Windows;
namespace WpfExtended.Blazor.Launch;
/// <summary>
/// Interaction logic for BlazorHostWindow.xaml
/// </summary>
public partial class BlazorHostWindow : Window
{
public static readonly DependencyProperty ServicesProperty = DependencyProperty.Register(
nameof(Services), typeof(IServiceProvider), typeof(BlazorHostWindow));
public static readonly DependencyProperty ShowTitleBarProperty = DependencyProperty.Register(
nameof(ShowTitleBar), typeof(bool), typeof(BlazorHostWindow));
public static readonly DependencyProperty HostPageProperty = DependencyProperty.Register(
nameof(HostPage), typeof(string), typeof(BlazorHostWindow));
public static readonly DependencyProperty AppTypeProperty = DependencyProperty.Register(
nameof(AppType), typeof(Type), typeof(BlazorHostWindow));
public event EventHandler<BlazorWebViewInitializedEventArgs>? BlazorWebViewInitialized;
public event EventHandler<BlazorWebViewInitializingEventArgs>? BlazorWebViewInitializing;
public event EventHandler<CoreWebView2InitializationCompletedEventArgs>? CoreWebView2InitializationCompleted;
public event EventHandler<CoreWebView2>? CoreWebView2Initialized;
public IServiceProvider Services
{
get => (IServiceProvider)this.GetValue(ServicesProperty);
set => this.SetValue(ServicesProperty, value);
}
public bool ShowTitleBar
{
get => (bool)this.GetValue(ShowTitleBarProperty);
set
{
this.SetValue(ShowTitleBarProperty, value);
this.WindowChrome.CaptionHeight = value ? SystemParameters.CaptionHeight : 0;
this.BlazorWebView.Margin = value ? new Thickness(0, SystemParameters.CaptionHeight, 0, 0) : new Thickness(0);
}
}
public string HostPage
{
get => (string)this.GetValue(HostPageProperty);
set => this.SetValue(HostPageProperty, value);
}
public Type AppType
{
get => (Type)this.GetValue(AppTypeProperty);
set
{
this.SetValue(AppTypeProperty, value);
this.RootComponent.ComponentType = value;
}
}
public BlazorHostWindow(
BlazorLaunchProperties blazorLaunchProperties,
IServiceProvider serviceProvider)
{
this.InitializeComponent();
this.Services = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
this.ShowTitleBar = blazorLaunchProperties.ShowTitleBar;
this.HostPage = blazorLaunchProperties.HostPage;
this.AppType = blazorLaunchProperties.AppType;
this.BlazorWebView.BlazorWebViewInitialized += this.BlazorWebView_BlazorWebViewInitialized;
this.BlazorWebView.BlazorWebViewInitializing += this.BlazorWebView_BlazorWebViewInitializing;
}
protected override void OnStateChanged(EventArgs e)
{
base.OnStateChanged(e);
var cornerRadius = Math.Max(
Math.Max(SystemParameters.WindowCornerRadius.TopLeft, SystemParameters.WindowCornerRadius.TopRight),
Math.Max(SystemParameters.WindowCornerRadius.BottomLeft, SystemParameters.WindowCornerRadius.BottomRight));
this.WindowChrome.ResizeBorderThickness = this.WindowState is WindowState.Maximized ? new Thickness(0) : new Thickness(cornerRadius);
this.WindowChrome.CornerRadius = this.WindowState is WindowState.Maximized ? new CornerRadius(0) : SystemParameters.WindowCornerRadius;
this.BlazorWebView.Margin = this.WindowState is WindowState.Maximized
? this.ShowTitleBar
? new Thickness(cornerRadius, SystemParameters.CaptionHeight + cornerRadius, cornerRadius, cornerRadius)
: new Thickness(cornerRadius)
: new Thickness(0, this.ShowTitleBar ? SystemParameters.CaptionHeight : 0, 0, 0);
}
private void BlazorWebView_BlazorWebViewInitialized(object? sender, BlazorWebViewInitializedEventArgs args)
{
args.WebView.CoreWebView2InitializationCompleted += this.CoreWebView2_InitializationCompleted;
this.BlazorWebViewInitialized?.Invoke(this, args);
}
private void BlazorWebView_BlazorWebViewInitializing(object? sender, BlazorWebViewInitializingEventArgs args)
{
this.BlazorWebViewInitializing?.Invoke(this, args);
}
private void CoreWebView2_InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
{
this.CoreWebView2InitializationCompleted?.Invoke(this, e);
if (!e.IsSuccess)
{
return;
}
if (sender is Microsoft.Web.WebView2.Wpf.WebView2 webView2)
{
this.CoreWebView2Initialized?.Invoke(this, webView2.CoreWebView2);
}
}
}
@@ -0,0 +1,78 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebView;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Web.WebView2.Core;
using System;
using System.Threading.Tasks;
using System.Windows.Extensions;
using WpfExtended.Blazor.Exceptions;
namespace WpfExtended.Blazor.Launch;
public abstract class BlazorHybridApplication<TApp> : ExtendedApplication<BlazorHostWindow>
where TApp : ComponentBase
{
public abstract bool DevToolsEnabled { get; }
public abstract string HostPage { get; }
public abstract bool ShowTitleBar { get; }
protected override void RegisterServices(IServiceCollection services)
{
services.AddSingleton(new BlazorLaunchProperties(typeof(TApp), this.HostPage, this.ShowTitleBar));
services.AddWpfBlazorWebView();
if (this.DevToolsEnabled)
{
services.AddBlazorWebViewDeveloperTools();
}
}
protected override ValueTask ApplicationStarting()
{
var host = this.ServiceProvider.GetRequiredService<BlazorHostWindow>();
host.BlazorWebViewInitializing += (_, e) => this.Host_BlazorWebViewInitializing(e);
host.BlazorWebViewInitialized += (_, e) => this.Host_BlazorWebViewInitialized(e);
host.CoreWebView2InitializationCompleted += (_, e) => this.Host_CoreWebView2InitializationCompleted(e);
host.CoreWebView2Initialized += (_, e) => this.Host_CoreWebView2Initialized(e);
return ValueTask.CompletedTask;
}
protected virtual void Host_CoreWebView2Initialized(CoreWebView2 e)
{
e.ProcessFailed += (_, ex) => this.CoreWebView2_ProcessFailed(ex);
}
protected virtual void Host_CoreWebView2InitializationCompleted(CoreWebView2InitializationCompletedEventArgs e)
{
if (e.InitializationException is not null)
{
this.HandleException(e.InitializationException);
return;
}
if (e.IsSuccess is false)
{
this.HandleException(new InvalidOperationException("CoreWebView2 initialization failed."));
return;
}
}
protected virtual void Host_BlazorWebViewInitialized(BlazorWebViewInitializedEventArgs e)
{
}
protected virtual void Host_BlazorWebViewInitializing(BlazorWebViewInitializingEventArgs e)
{
}
private void CoreWebView2_ProcessFailed(CoreWebView2ProcessFailedEventArgs e)
{
var exception = new CoreWebView2Exception(e, "Encountered exception in CoreWebView2");
if (!this.HandleException(exception))
{
throw exception;
}
}
}
@@ -0,0 +1,7 @@
using System;
namespace WpfExtended.Blazor.Launch;
public sealed record BlazorLaunchProperties(Type AppType, string HostPage, bool ShowTitleBar)
{
}
@@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks>net10.0-windows10.0.17763.0</TargetFrameworks>
<UseWPF>true</UseWPF>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>0.9.0</Version>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<Description>
Extension library for Blazor Hybrid running on Windows Presentation Platform.
</Description>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/WpfExtended</RepositoryUrl>
<!-- Disable static web asset props file generation for consumers -->
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
<GenerateStaticWebAssetsManifest>false</GenerateStaticWebAssetsManifest>
<GenerateStaticWebAssetEndpointsManifest>false</GenerateStaticWebAssetEndpointsManifest>
<GenerateStaticWebAssetEndpointsPropsFile>false</GenerateStaticWebAssetEndpointsPropsFile>
<DisableStaticWebAssetsBuildPropsFileGeneration>true</DisableStaticWebAssetsBuildPropsFileGeneration>
<IncludeStaticWebAssetsPackItems>false</IncludeStaticWebAssetsPackItems>
</PropertyGroup>
<!-- Remove auto-generated build props/targets from the NuGet package -->
<Target Name="RemoveStaticWebAssetsPropsFromPackage" BeforeTargets="GenerateNuspec">
<ItemGroup>
<_PackageFiles Remove="@(_PackageFiles)"
Condition="'%(Identity)' != '' And $([System.String]::new('%(Identity)').Contains('StaticWebAssets'))" />
<_PackageFiles Remove="@(_PackageFiles)"
Condition="'%(Identity)' != '' And $([System.String]::new('%(Identity)').EndsWith('.props'))" />
<_PackageFiles Remove="@(_PackageFiles)"
Condition="'%(Identity)' != '' And $([System.String]::new('%(Identity)').EndsWith('.targets'))" />
</ItemGroup>
</Target>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components" Version="10.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Wpf" Version="10.0.20" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3650.58" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WpfExtended\WpfExtended.csproj" />
</ItemGroup>
</Project>
@@ -1,24 +0,0 @@
using FluentAssertions;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media.Effects;
namespace WpfExtended.SourceGeneration.Tests
{
internal partial class Class1 : UserControl
{
[GenerateDependencyProperty]
public int someF;
[GenerateDependencyProperty(InitialValue = "This has a value")]
public string someValue;
[GenerateDependencyProperty]
public Effect effect;
public void TestValues()
{
this.SomeF.Should().Be(0);
this.SomeValue.Should().Be("This has a value");
this.Effect.Should().BeNull();
}
}
}
@@ -1,15 +0,0 @@
using System;
namespace WpfExtended.SourceGeneration.Tests
{
public class Launcher
{
[STAThread]
public static int Main()
{
var cls = new Class1();
cls.TestValues();
return 0;
}
}
}
@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<LangVersion>preview</LangVersion>
<OutputType>Exe</OutputType>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>obj</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.0.0-alpha0002" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WpfExtended.SourceGeneration\WpfExtended.SourceGeneration.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
-143
View File
@@ -1,143 +0,0 @@
using System.Extensions.Templates;
using System.Linq;
using System.Text;
namespace System.Extensions
{
internal class CodeWriter
{
private StringBuilder StringBuilder { get; } = new StringBuilder();
private CodeBlock CurrentBlock { get; set; } = new CodeBlock();
public CodeWriter Append(string value)
{
this.CurrentBlock.Append(this.StringBuilder, value);
return this;
}
public CodeWriter AppendLine(string value)
{
this.CurrentBlock.AppendLine(this.StringBuilder, value);
return this;
}
public CodeWriter AppendLine()
{
this.CurrentBlock.AppendLine(this.StringBuilder);
return this;
}
public CodeWriter Append(char c)
{
this.CurrentBlock.Append(this.StringBuilder, c);
return this;
}
public CodeWriter AppendLine(char c)
{
this.AppendLine(c);
return this;
}
public CodeWriter Append(AbstractTemplate abstractTemplate)
{
abstractTemplate.Generate(this);
return this;
}
public CodeWriter BeginCodeBlock()
{
this.CurrentBlock.AppendLine(this.StringBuilder).AppendLine(this.StringBuilder, '{');
this.CurrentBlock = CodeBlock.GenerateCodeBlock(this.CurrentBlock);
return this;
}
public CodeWriter EndCodeBlock()
{
this.CurrentBlock = this.CurrentBlock.End(this.StringBuilder).Parent;
this.CurrentBlock.AppendLine(this.StringBuilder, '}');
return this;
}
public override string ToString()
{
return this.StringBuilder.ToString();
}
private class CodeBlock
{
private const char PrefixSymbol = '\t';
private bool NewLine { get; set; } = true;
private string Prefix { get; }
public CodeBlock Parent { get; }
public int Level { get; }
public CodeBlock()
{
this.Level = 0;
this.Prefix = string.Empty;
}
private CodeBlock(int level, CodeBlock parent)
{
this.Level = level;
this.Prefix = new string(Enumerable.Repeat(PrefixSymbol, this.Level).ToArray());
this.Parent = parent;
}
public CodeBlock AppendLine(StringBuilder stringBuilder)
{
stringBuilder.AppendLine();
this.NewLine = true;
return this;
}
public CodeBlock AppendLine(StringBuilder stringBuilder, string value)
{
value = this.NewLine is true ? Prefix + value : value;
stringBuilder.AppendLine(value);
this.NewLine = true;
return this;
}
public CodeBlock Append(StringBuilder stringBuilder, string value)
{
value = this.NewLine is true ? Prefix + value : value;
stringBuilder.Append(value);
this.NewLine = false;
return this;
}
public CodeBlock Append(StringBuilder stringBuilder, char c)
{
var value = this.NewLine is true ? Prefix + c : c.ToString();
stringBuilder.Append(value);
this.NewLine = false;
return this;
}
public CodeBlock AppendLine(StringBuilder stringBuilder, char c)
{
var value = this.NewLine is true ? Prefix + c : c.ToString();
stringBuilder.AppendLine(value);
this.NewLine = true;
return this;
}
public CodeBlock End(StringBuilder stringBuilder)
{
if (this.NewLine is false)
{
stringBuilder.AppendLine();
this.NewLine = true;
}
return this;
}
public static CodeBlock GenerateCodeBlock(CodeBlock codeBlock)
{
var child = new CodeBlock(codeBlock.Level + 1, codeBlock);
return child;
}
}
}
}
@@ -1,196 +1,189 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using System.Diagnostics;
using Sybil;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Extensions.Templates;
namespace System.Extensions
namespace System.Extensions;
#nullable enable
[Generator(LanguageNames.CSharp)]
public class DependencyPropertyGenerator : IIncrementalGenerator
{
[Generator]
public class DependencyPropertyGenerator : ISourceGenerator
private const string DependencyPropertyNamespace = "System.Windows";
private const string AttributeNamespace = "System.Windows.Extensions";
private const string AttributeName = "GenerateDependencyPropertyAttribute";
private const string AttributeShortName = "GenerateDependencyProperty";
private const string DependencyPropertySuffix = "Property";
private const string DependencyProperty = "DependencyProperty";
private const string Register = "Register";
private const string Partial = "partial";
private const string Public = "public";
private const string Static = "static";
private const string Readonly = "readonly";
private const string InitialValue = "InitialValue";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
private const string AttributeNamespace = "System.Windows.Extensions";
private const string AttributeName = "GenerateDependencyPropertyAttribute";
private const string DependencyPropertySuffix = "Property";
private static readonly ClassTemplate GenerateDependencyPropertyAttribute =
new ClassTemplate()
.WithUsings(
new UsingsTemplate()
.WithNamespace("System"))
.WithNamespace(
new NamespaceTemplate()
.WithNamespace(AttributeNamespace))
.WithConstructor(
new ConstructorTemplate()
.WithType(AttributeName)
.WithModifiers(Modifier.Public))
.WithAttributes(
new AttributeTemplate()
.WithAttribute("AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)"))
.WithModifiers(Modifier.Public, Modifier.Sealed)
.WithName(AttributeName)
.WithBase("Attribute")
.WithProperty(
new PropertyTemplate()
.WithModifiers(Modifier.Public)
.WithName("InitialValue")
.WithType("object"));
public void Initialize(GeneratorInitializationContext context)
context.RegisterPostInitializationOutput(context =>
{
// Register a syntax receiver that will be created for each generation pass
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
var compilationUnitBuilder =
SyntaxBuilder.CreateCompilationUnit()
.WithUsing("System.ComponentModel")
.WithNamespace(
SyntaxBuilder.CreateNamespace(AttributeNamespace)
.WithClass(SyntaxBuilder.CreateClass(AttributeName)
.WithModifier(Public)
.WithConstructor(SyntaxBuilder.CreateConstructor(AttributeName)
.WithModifier(Public))
.WithAttribute(SyntaxBuilder.CreateAttribute("AttributeUsage")
.WithArgument(AttributeTargets.Field)
.WithArgument("Inherited", false)
.WithArgument("AllowMultiple", false))
.WithBaseClass(nameof(Attribute))
.WithProperty(SyntaxBuilder.CreateProperty("object", InitialValue)
.WithModifier(Public)
.WithAccessor(SyntaxBuilder.CreateGetter())
.WithAccessor(SyntaxBuilder.CreateSetter()))));
var compilationUnitSyntax = compilationUnitBuilder.Build();
var source = compilationUnitSyntax.ToFullString();
context.AddSource($"{AttributeName}.g", source);
});
var classDeclarations = context.SyntaxProvider.CreateSyntaxProvider(
predicate: static (s, _) => s is FieldDeclarationSyntax,
transform: static (ctx, _) => GetFilteredFieldDeclarationSyntax(ctx)).Where(static c => c is not null);
var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
context.RegisterSourceOutput(compilationAndClasses, (sourceProductionContext, tuple) => Execute(tuple.Left, tuple.Right, sourceProductionContext));
}
private static ClassDeclarationSyntax? GetFilteredFieldDeclarationSyntax(GeneratorSyntaxContext context)
{
var fieldDeclarationSyntax = (FieldDeclarationSyntax)context.Node;
if (fieldDeclarationSyntax.AttributeLists
.SelectMany(l => l.Attributes)
.OfType<AttributeSyntax>()
.Any(s => s.Name.ToString() == AttributeName || s.Name.ToString() == AttributeShortName))
{
return fieldDeclarationSyntax.Parent as ClassDeclarationSyntax;
}
public void Execute(GeneratorExecutionContext context)
return default;
}
private static void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyntax?> classes, SourceProductionContext sourceProductionContext)
{
if (classes.IsDefaultOrEmpty)
{
var attributeText = GenerateDependencyPropertyAttribute.GenerateString();
context.AddSource("GenerateDependencyPropertyAttribute.g", attributeText);
return;
}
if (context.SyntaxReceiver is not SyntaxReceiver receiver)
return;
var maybeLanguageVersion = (compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions)?.LanguageVersion;
if (!maybeLanguageVersion.HasValue)
{
return;
}
var options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions;
var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(attributeText, Encoding.UTF8), options));
var attributeSymbol = compilation.GetTypeByMetadataName($"{AttributeNamespace}.{AttributeName}");
if (attributeSymbol is null)
var languageVersion = maybeLanguageVersion.Value;
var distinctClasses = classes.Distinct();
foreach (var c in distinctClasses.OfType<ClassDeclarationSyntax>())
{
var className = c.Identifier.ToFullString().Trim();
if (!c.Modifiers.Any(m => m.ToString() == Partial))
{
context.ReportDiagnostic(Diagnostics.MissingAttributeDiagnostic(AttributeName, AttributeNamespace));
return;
Diagnostics.ClassNotPartial(className);
continue;
}
var fieldSymbols = new List<IFieldSymbol>();
foreach (var field in receiver.CandidateFields)
var originalNamespaceSyntax = GetParentOfType<BaseNamespaceDeclarationSyntax>(c);
if (originalNamespaceSyntax is null)
{
var model = compilation.GetSemanticModel(field.SyntaxTree);
foreach (var variable in field.Declaration.Variables)
Diagnostics.ClassNotInNamespace(className);
continue;
}
var generatedClassBuilder = SyntaxBuilder.CreateClass(className)
.WithModifiers(string.Join(" ", c.Modifiers.Select(m => m.ToFullString())));
var generatedCompilationUnit = SyntaxBuilder.CreateCompilationUnit()
.WithNamespace(
(languageVersion >= LanguageVersion.CSharp10 ?
SyntaxBuilder.CreateFileScopedNamespace(originalNamespaceSyntax.Name.ToFullString()) :
SyntaxBuilder.CreateNamespace(originalNamespaceSyntax.Name.ToFullString()))
.WithClass(generatedClassBuilder));
if (originalNamespaceSyntax.Usings.OfType<UsingDirectiveSyntax>().Any(u => u.Name?.ToString() == DependencyPropertyNamespace) is false &&
(originalNamespaceSyntax.Parent as CompilationUnitSyntax)?.Usings.Any(u => u.Name?.ToString() == DependencyPropertyNamespace) is false)
{
generatedCompilationUnit.WithUsing(DependencyPropertyNamespace);
}
foreach (var field in c.DescendantNodes().OfType<FieldDeclarationSyntax>())
{
var attributeSyntax = field.AttributeLists
.SelectMany(l => l.Attributes)
.OfType<AttributeSyntax>()
.FirstOrDefault(s => s.Name.ToString() == AttributeName ||
s.Name.ToString() == AttributeShortName);
if (attributeSyntax is null)
{
var fieldSymbol = model.GetDeclaredSymbol(variable) as IFieldSymbol;
if (fieldSymbol.GetAttributes().Any(ad => ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default)))
{
fieldSymbols.Add(fieldSymbol);
}
continue;
}
var initialValueArgument = attributeSyntax.ArgumentList?.Arguments
.FirstOrDefault(arg => arg.NameEquals != null && arg.NameEquals.Name.Identifier.ValueText == InitialValue);
var fieldName = field.Declaration.Variables.First().Identifier.ToFullString().Trim();
var fieldType = field.Declaration.Type.ToFullString().Trim();
var propertyName = fieldName.TrimStart('_');
propertyName = $"{char.ToUpper(propertyName[0])}{propertyName.Substring(1)}".Trim();
var dependencyPropertyName = $"{propertyName.Trim()}{DependencyPropertySuffix}".Trim();
var propertyBuilder = SyntaxBuilder.CreateProperty(fieldType, propertyName)
.WithModifier(Public)
.WithAccessor(SyntaxBuilder.CreateGetter()
.WithBody($"this.{fieldName} = ({fieldType})this.GetValue({dependencyPropertyName});\r\nreturn this.{fieldName};"))
.WithAccessor(SyntaxBuilder.CreateSetter()
.WithBody($"this.{fieldName} = value;\r\nthis.SetValue({dependencyPropertyName}, value);"));
var dependencyPropertyFieldBuilder = SyntaxBuilder.CreateField(DependencyProperty, dependencyPropertyName)
.WithModifiers($"{Public} {Static} {Readonly}")
.WithInitializer($"{DependencyProperty}.Register(nameof({propertyName}), typeof({fieldType}), typeof({className}), new PropertyMetadata({initialValueArgument?.Expression.ToString()}))");
generatedClassBuilder
.WithProperty(propertyBuilder)
.WithField(dependencyPropertyFieldBuilder);
}
foreach (var group in fieldSymbols.GroupBy(f => f.ContainingType, SymbolEqualityComparer.IncludeNullability))
var generatedSyntax = generatedCompilationUnit.Build();
if (originalNamespaceSyntax.Usings.Count != 0)
{
var classSource = ProcessClass((INamedTypeSymbol)group.Key, attributeSymbol, group.ToList(), context);
context.ReportDiagnostic(Diagnostics.GeneratedSymbolsForClassDiagnostic(group.Key.Name));
context.AddSource($"{group.Key.Name}.DependencyPropertyGenerator.g.cs", classSource);
}
}
private static string ProcessClass(INamedTypeSymbol classSymbol, INamedTypeSymbol attributeSymbol, List<IFieldSymbol> fields, GeneratorExecutionContext generatorExecutionContext)
{
if (!classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.Default))
{
var syntaxTree = classSymbol.DeclaringSyntaxReferences.First().SyntaxTree;
var textSpan = classSymbol.DeclaringSyntaxReferences.First().Span;
generatorExecutionContext.ReportDiagnostic(
Diagnostics.ClassNotTopLevelDiagnostic(classSymbol.Name, classSymbol.ContainingSymbol.Name, syntaxTree, textSpan));
return null;
}
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
var source = new ClassTemplate()
.WithUsings(
new UsingsTemplate()
.WithNamespace("System"),
new UsingsTemplate()
.WithNamespace("System.Windows"))
.WithNamespace(
new NamespaceTemplate()
.WithNamespace(namespaceName))
.WithName(classSymbol.Name);
AssignModifiers(source, classSymbol);
foreach (var fieldSymbol in fields)
{
ProcessField(source, classSymbol, attributeSymbol, fieldSymbol);
}
return source.GenerateString();
}
private static void AssignModifiers(ClassTemplate source, INamedTypeSymbol classSymbol)
{
//Find class declaration syntax and parse modifiers.
if (classSymbol.DeclaringSyntaxReferences.Select(sr => sr.GetSyntax()).OfType<ClassDeclarationSyntax>().First() is ClassDeclarationSyntax classDeclarationSyntax)
{
source.WithModifiers(classDeclarationSyntax.Modifiers.Select(m => Modifier.Parse(m.ValueText)).ToArray());
}
}
private static void ProcessField(ClassTemplate source, INamedTypeSymbol classSymbol, INamedTypeSymbol attributeSymbol, IFieldSymbol fieldSymbol)
{
var fieldName = fieldSymbol.Name;
var fieldType = fieldSymbol.Type;
string propertyName = GenerateName(fieldName);
var attributeData = fieldSymbol.GetAttributes().Single(ad => ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default));
var initialValueOpt = attributeData.NamedArguments.SingleOrDefault(kvp => kvp.Key == "InitialValue").Value;
var dependencyPropertyValue = initialValueOpt.Value is null ?
@$"DependencyProperty.Register(""{propertyName}"", typeof({fieldType}), typeof({classSymbol.Name}))" :
@$"DependencyProperty.Register(""{propertyName}"", typeof({fieldType}), typeof({classSymbol.Name}), new PropertyMetadata({initialValueOpt.ToCSharpString()}))";
source
.WithField(
new FieldTemplate()
.WithModifiers(Modifier.Public, Modifier.Static, Modifier.Readonly)
.WithType("DependencyProperty")
.WithName(propertyName + DependencyPropertySuffix)
.WithValue(dependencyPropertyValue))
.WithProperty(
new PropertyTemplate()
.WithType(fieldType.ToString())
.WithName(propertyName)
.WithGetter(
new GetterTemplate()
.WithCode(
new CodeBlockTemplate()
.WithLine($"this.{fieldName} = ({fieldType})this.GetValue({propertyName + DependencyPropertySuffix});")
.WithLine($"return ({fieldType})this.GetValue({propertyName + DependencyPropertySuffix});")))
.WithSetter(
new SetterTemplate()
.WithCode(
new CodeBlockTemplate()
.WithLine($"this.{fieldName} = value;")
.WithLine($"this.SetValue({propertyName + DependencyPropertySuffix}, value);"))));
}
private static string GenerateName(string fieldName)
{
fieldName = fieldName.TrimStart('_');
if (char.IsUpper(fieldName.First()))
{
return char.ToLower(fieldName.First()) + fieldName.Substring(1);
generatedSyntax = generatedSyntax.AddUsings([.. originalNamespaceSyntax.Usings]);
}
else
{
return char.ToUpper(fieldName.First()) + fieldName.Substring(1);
}
}
internal class SyntaxReceiver : ISyntaxReceiver
{
public List<FieldDeclarationSyntax> CandidateFields { get; } = new List<FieldDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is FieldDeclarationSyntax fieldDeclarationSyntax &&
fieldDeclarationSyntax.AttributeLists.Count > 0)
if (originalNamespaceSyntax.Parent is CompilationUnitSyntax compilationUnit)
{
this.CandidateFields.Add(fieldDeclarationSyntax);
generatedSyntax = generatedSyntax.AddUsings([.. compilationUnit.Usings]);
}
}
var fileSource = generatedSyntax.ToFullString();
sourceProductionContext.AddSource($"{className}.g", fileSource);
}
}
private static T? GetParentOfType<T>(SyntaxNode syntaxNode)
{
if (syntaxNode.Parent is null)
{
return default;
}
if (syntaxNode.Parent is T parentNode)
{
return parentNode;
}
return GetParentOfType<T>(syntaxNode.Parent);
}
}
#nullable disable
+41 -13
View File
@@ -7,7 +7,9 @@ namespace System.Extensions
{
public const string DependencyPropertyGenerator_NoAttributeFound = "DGD 0001";
public const string DependencyPropertyGenerator_ClassMustBeTopLevel = "DGD 1001";
public const string DependencyPropertyGenerator_Success = "DGD 3001";
public const string DependencyPropertyGenerator_ClassMustBePartial = "DGD 1002";
public const string DependencyPropertyGenerator_ClassMustBeInNamespace = "DGD 1003";
public const string DependencyPropertyGenerator_ClassMustImplementINotifyPropertyChanged = "DGD 1004";
public static Diagnostic MissingAttributeDiagnostic(string attributeName, string attributeNamespace) => Diagnostic.Create(
new DiagnosticDescriptor(
@@ -35,17 +37,43 @@ namespace System.Extensions
Location.Create(syntaxTree, textSpan),
className, containingSymbol);
public static Diagnostic GeneratedSymbolsForClassDiagnostic(string className) => Diagnostic.Create(
new DiagnosticDescriptor(
DependencyPropertyGenerator_Success,
$"{className} created dependency properties",
"DependencyPropertyGenerator successfully created implementations for properties in {0}",
"WpfExtended.SourceGeneration",
DiagnosticSeverity.Info,
true,
null,
null),
Location.None,
className);
public static Diagnostic ClassNotPartial(string className) => Diagnostic.Create(
new DiagnosticDescriptor(
DependencyPropertyGenerator_ClassMustBePartial,
$"{className} is not partial",
"Class {0} must be marked as partial in order for the generator to work",
"WpfExtended.SourceGeneration",
DiagnosticSeverity.Error,
true,
null,
null),
Location.None,
className);
public static Diagnostic ClassNotInNamespace(string className) => Diagnostic.Create(
new DiagnosticDescriptor(
DependencyPropertyGenerator_ClassMustBeInNamespace,
$"{className} is not defined in a namespace",
"Class {0} must be defined inside a namespace for the generator to work",
"WpfExtended.SourceGeneration",
DiagnosticSeverity.Error,
true,
null,
null),
Location.None,
className);
public static Diagnostic ClassDoesNotImplementINotifyPropertyChanged(string className) => Diagnostic.Create(
new DiagnosticDescriptor(
DependencyPropertyGenerator_ClassMustImplementINotifyPropertyChanged,
$"{className} must implement INotifyPropertyChanged",
"Class {0} must implement INotifyPropertyChanged for the generator to work",
"WpfExtended.SourceGeneration",
DiagnosticSeverity.Error,
true,
null,
null),
Location.None,
className);
}
}
@@ -0,0 +1,174 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Sybil;
using System.Linq;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp;
using System.Diagnostics;
namespace System.Extensions;
#nullable enable
[Generator(LanguageNames.CSharp)]
public class NotifyPropertyChangedGenerator : IIncrementalGenerator
{
private const string AttributeNamespace = "System.Windows.Extensions";
private const string AttributeName = "GenerateNotifyPropertyChangedAttribute";
private const string AttributeShortName = "GenerateNotifyPropertyChanged";
private const string PropertyChangedEventHandler = "PropertyChangedEventHandler";
private const string NullablePropertyChangedEventHandler = "PropertyChangedEventHandler?";
private const string PropertyChanged = "PropertyChanged";
private const string Partial = "partial";
private const string Public = "public";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(context =>
{
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
.WithNamespace(
SyntaxBuilder.CreateNamespace(AttributeNamespace)
.WithClass(SyntaxBuilder.CreateClass(AttributeName)
.WithModifier(Public)
.WithConstructor(SyntaxBuilder.CreateConstructor(AttributeName)
.WithModifier(Public))
.WithAttribute(SyntaxBuilder.CreateAttribute("AttributeUsage")
.WithArgument(AttributeTargets.Field)
.WithArgument("Inherited", false)
.WithArgument("AllowMultiple", false))
.WithBaseClass(nameof(Attribute))));
var compilationUnitSyntax = compilationUnitBuilder.Build();
var source = compilationUnitSyntax.ToFullString();
context.AddSource($"{AttributeName}.g", source);
});
var classDeclarations = context.SyntaxProvider.CreateSyntaxProvider(
predicate: static (s, _) => s is FieldDeclarationSyntax,
transform: static (ctx, _) => GetFilteredFieldDeclarationSyntax(ctx)).Where(static c => c is not null);
var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
context.RegisterSourceOutput(compilationAndClasses, (sourceProductionContext, tuple) => Execute(tuple.Left, tuple.Right, sourceProductionContext));
}
private static ClassDeclarationSyntax? GetFilteredFieldDeclarationSyntax(GeneratorSyntaxContext context)
{
var fieldDeclarationSyntax = (FieldDeclarationSyntax)context.Node;
if (fieldDeclarationSyntax.AttributeLists
.SelectMany(l => l.Attributes)
.OfType<AttributeSyntax>()
.Any(s => s.Name.ToString() == AttributeName || s.Name.ToString() == AttributeShortName))
{
return fieldDeclarationSyntax.Parent as ClassDeclarationSyntax;
}
return default;
}
private static void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyntax?> classes, SourceProductionContext sourceProductionContext)
{
if (classes.IsDefaultOrEmpty)
{
return;
}
var maybeLanguageVersion = (compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions)?.LanguageVersion;
if (!maybeLanguageVersion.HasValue)
{
return;
}
var languageVersion = maybeLanguageVersion.Value;
var distinctClasses = classes.Distinct();
foreach (var c in distinctClasses.OfType<ClassDeclarationSyntax>())
{
var className = c.Identifier.ToFullString();
if (!c.Modifiers.Any(m => m.ToString() == Partial))
{
Diagnostics.ClassNotPartial(className);
continue;
}
var originalNamespaceSyntax = GetParentOfType<BaseNamespaceDeclarationSyntax>(c);
if (originalNamespaceSyntax is null)
{
Diagnostics.ClassNotInNamespace(className);
continue;
}
if (!c.Members
.OfType<EventFieldDeclarationSyntax>()
.Any(eventField =>
(eventField.Declaration.Variables.Any(variable => variable.Identifier.Text == PropertyChanged) &&
eventField.Modifiers.Any(modifier => modifier.Text == Public) &&
eventField.Declaration.Type.ToString() == PropertyChangedEventHandler) ||
eventField.Declaration.Type.ToString() == NullablePropertyChangedEventHandler))
{
Diagnostics.ClassDoesNotImplementINotifyPropertyChanged(className);
continue;
}
var generatedClassBuilder = SyntaxBuilder.CreateClass(className)
.WithModifiers(string.Join(" ", c.Modifiers.Select(m => m.ToFullString())));
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
.WithNamespace(
(languageVersion >= LanguageVersion.CSharp10 ?
SyntaxBuilder.CreateFileScopedNamespace(originalNamespaceSyntax.Name.ToFullString()) :
SyntaxBuilder.CreateNamespace(originalNamespaceSyntax.Name.ToFullString()))
.WithClass(generatedClassBuilder));
foreach (var field in c.DescendantNodes().OfType<FieldDeclarationSyntax>())
{
if (field.AttributeLists
.SelectMany(l => l.Attributes)
.OfType<AttributeSyntax>()
.Any(s => s.Name.ToString() == AttributeName ||
s.Name.ToString() == AttributeShortName) is false)
{
continue;
}
var fieldName = field.Declaration.Variables.First().Identifier.ToFullString();
var propertyName = fieldName.TrimStart('_');
propertyName = $"{char.ToUpper(propertyName[0])}{propertyName.Substring(1)}";
var propertyBuilder = SyntaxBuilder.CreateProperty(field.Declaration.Type.ToFullString(), propertyName)
.WithModifier(Public)
.WithAccessor(SyntaxBuilder.CreateGetter()
.WithBody($"return this.{fieldName};"))
.WithAccessor(SyntaxBuilder.CreateSetter()
.WithBody($"this.{fieldName} = value;\r\nthis.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof({propertyName})));"));
generatedClassBuilder.WithProperty(propertyBuilder);
}
var generatedSyntax = compilationUnitBuilder.Build();
if (originalNamespaceSyntax.Usings.Count != 0)
{
generatedSyntax = generatedSyntax.AddUsings([.. originalNamespaceSyntax.Usings]);
}
else
{
if (originalNamespaceSyntax.Parent is CompilationUnitSyntax compilationUnit)
{
generatedSyntax = generatedSyntax.AddUsings([.. compilationUnit.Usings]);
}
}
var fileSource = generatedSyntax.ToFullString();
sourceProductionContext.AddSource($"{className}.g", fileSource);
}
}
private static T? GetParentOfType<T>(SyntaxNode syntaxNode)
{
if (syntaxNode.Parent is null)
{
return default;
}
if (syntaxNode.Parent is T parentNode)
{
return parentNode;
}
return GetParentOfType<T>(syntaxNode.Parent);
}
}
#nullable disable
@@ -1,7 +0,0 @@
namespace System.Extensions.Templates
{
internal abstract class AbstractTemplate
{
public abstract void Generate(CodeWriter codeWriter);
}
}
@@ -1,28 +0,0 @@
namespace System.Extensions.Templates
{
internal sealed class ArgumentTemplate : AbstractTemplate
{
public string Name { get; set; }
public string Type { get; set; }
public ArgumentTemplate WithName(string name)
{
this.Name = name;
return this;
}
public ArgumentTemplate WithType(string type)
{
this.Type = type;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
codeWriter
.Append(this.Type)
.Append(' ')
.Append(this.Name);
}
}
}
@@ -1,21 +0,0 @@
namespace System.Extensions.Templates
{
internal sealed class AttributeTemplate : AbstractTemplate
{
public string Attribute { get; set; }
public AttributeTemplate WithAttribute(string attribute)
{
this.Attribute = attribute;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
codeWriter
.Append('[')
.Append(this.Attribute)
.Append(']');
}
}
}
@@ -1,190 +0,0 @@
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class ClassTemplate : AbstractTemplate
{
public List<AttributeTemplate> Attributes { get; } = new List<AttributeTemplate>();
public List<UsingsTemplate> Usings { get; } = new List<UsingsTemplate>();
public List<Modifier> Modifiers { get; } = new List<Modifier>();
public List<PropertyTemplate> Properties { get; } = new List<PropertyTemplate>();
public List<FieldTemplate> Fields { get; } = new List<FieldTemplate>();
public List<MethodTemplate> Methods { get; } = new List<MethodTemplate>();
public List<ConstructorTemplate> Constructors { get; } = new List<ConstructorTemplate>();
public NamespaceTemplate Namespace { get; set; }
public string Name { get; set; }
public string Base { get; set; }
public ClassTemplate WithAttributes(params AttributeTemplate[] attributeTemplates)
{
this.Attributes.Clear();
this.Attributes.AddRange(attributeTemplates);
return this;
}
public ClassTemplate WithAttribute(AttributeTemplate attributeTemplate)
{
this.Attributes.Add(attributeTemplate);
return this;
}
public ClassTemplate WithUsings(params UsingsTemplate[] usingsTemplates)
{
this.Usings.Clear();
this.Usings.AddRange(usingsTemplates);
return this;
}
public ClassTemplate WithUsing(UsingsTemplate usingsTemplate)
{
this.Usings.Add(usingsTemplate);
return this;
}
public ClassTemplate WithModifiers(params Modifier[] modifiers)
{
this.Modifiers.Clear();
this.Modifiers.AddRange(modifiers);
return this;
}
public ClassTemplate WithModifier(Modifier modifier)
{
this.Modifiers.Add(modifier);
return this;
}
public ClassTemplate WithMethods(params MethodTemplate[] methodTemplates)
{
this.Methods.Clear();
this.Methods.AddRange(methodTemplates);
return this;
}
public ClassTemplate WithMethod(MethodTemplate methodTemplate)
{
this.Methods.Add(methodTemplate);
return this;
}
public ClassTemplate WithFields(params FieldTemplate[] fieldTemplates)
{
this.Fields.Clear();
this.Fields.AddRange(fieldTemplates);
return this;
}
public ClassTemplate WithField(FieldTemplate fieldTemplate)
{
this.Fields.Add(fieldTemplate);
return this;
}
public ClassTemplate WithProperties(params PropertyTemplate[] propertyTemplates)
{
this.Properties.Clear();
this.Properties.AddRange(propertyTemplates);
return this;
}
public ClassTemplate WithProperty(PropertyTemplate propertyTemplate)
{
this.Properties.Add(propertyTemplate);
return this;
}
public ClassTemplate WithConstructors(params ConstructorTemplate[] constructorTemplates)
{
this.Constructors.Clear();
this.Constructors.AddRange(constructorTemplates);
return this;
}
public ClassTemplate WithConstructor(ConstructorTemplate constructorTemplate)
{
this.Constructors.Add(constructorTemplate);
return this;
}
public ClassTemplate WithNamespace(NamespaceTemplate namespaceTemplate)
{
this.Namespace = namespaceTemplate;
return this;
}
public ClassTemplate WithName(string name)
{
this.Name = name;
return this;
}
public ClassTemplate WithBase(string b)
{
this.Base = b;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach(var u in this.Usings)
{
codeWriter
.Append(u)
.AppendLine();
}
codeWriter
.AppendLine()
.Append(this.Namespace)
.BeginCodeBlock();
foreach(var attribute in this.Attributes)
{
codeWriter
.Append(attribute)
.AppendLine();
}
foreach(var modifier in this.Modifiers)
{
codeWriter
.Append(modifier)
.Append(' ');
}
codeWriter
.Append("class")
.Append(' ')
.Append(this.Name);
if (!string.IsNullOrEmpty(this.Base))
{
codeWriter
.Append(' ')
.Append(':')
.Append(' ')
.Append(this.Base);
}
codeWriter.BeginCodeBlock();
foreach(var field in this.Fields)
{
codeWriter
.Append(field)
.AppendLine();
}
foreach(var property in this.Properties)
{
codeWriter
.Append(property)
.AppendLine();
}
foreach(var constructor in this.Constructors)
{
codeWriter
.Append(constructor)
.AppendLine();
}
foreach(var method in this.Methods)
{
codeWriter
.Append(method)
.AppendLine();
}
codeWriter.EndCodeBlock().EndCodeBlock();
}
public string GenerateString()
{
var codeWriter = new CodeWriter();
this.Generate(codeWriter);
return codeWriter.ToString();
}
}
}
@@ -1,30 +0,0 @@
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class CodeBlockTemplate : CodeTemplate
{
public List<string> Lines { get; set; } = new List<string>();
public CodeBlockTemplate WithLines(params string[] lines)
{
this.Lines.Clear();
this.Lines.AddRange(lines);
return this;
}
public CodeBlockTemplate WithLine(string line)
{
this.Lines.Add(line);
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach(var line in this.Lines)
{
codeWriter.AppendLine(line);
}
}
}
}
@@ -1,6 +0,0 @@
namespace System.Extensions.Templates
{
internal abstract class CodeTemplate : AbstractTemplate
{
}
}
@@ -1,82 +0,0 @@
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class ConstructorTemplate : AbstractTemplate
{
public List<Modifier> Modifiers { get; } = new List<Modifier>();
public List<ArgumentTemplate> Arguments { get; } = new List<ArgumentTemplate>();
public string Type { get; set; }
public string Body { get; set; }
public string Base { get; set; }
public ConstructorTemplate WithType(string type)
{
this.Type = type;
return this;
}
public ConstructorTemplate WithBody(string body)
{
this.Body = body;
return this;
}
public ConstructorTemplate WithBase(string b)
{
this.Base = b;
return this;
}
public ConstructorTemplate WithModifiers(params Modifier[] modifiers)
{
this.Modifiers.Clear();
this.Modifiers.AddRange(modifiers);
return this;
}
public ConstructorTemplate WithArguments(params ArgumentTemplate[] argumentTemplates)
{
this.Arguments.Clear();
this.Arguments.AddRange(argumentTemplates);
return this;
}
public ConstructorTemplate WithArgument(ArgumentTemplate argumentTemplate)
{
this.Arguments.Add(argumentTemplate);
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach(var modifier in this.Modifiers)
{
codeWriter
.Append(modifier)
.Append(' ');
}
codeWriter
.Append(this.Type)
.Append('(');
for (int i = 0; i < this.Arguments.Count; i++)
{
var argument = this.Arguments[i];
codeWriter.Append(argument);
if (i < this.Arguments.Count - 1)
{
codeWriter.Append(", ");
}
}
codeWriter.Append(')');
if (!string.IsNullOrEmpty(this.Base))
{
codeWriter
.Append(" : base(")
.Append(this.Base)
.Append(')');
}
codeWriter.BeginCodeBlock()
.Append(this.Body)
.EndCodeBlock();
}
}
}
@@ -1,55 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Extensions.Templates
{
internal sealed class FieldTemplate : AbstractTemplate
{
public List<Modifier> Modifiers { get; } = new List<Modifier> { Modifier.Public };
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
public FieldTemplate WithName(string name)
{
this.Name = name;
return this;
}
public FieldTemplate WithValue(string value)
{
this.Value = value;
return this;
}
public FieldTemplate WithModifiers(params Modifier[] modifiers)
{
this.Modifiers.Clear();
this.Modifiers.AddRange(modifiers);
return this;
}
public FieldTemplate WithType(string type)
{
this.Type = type;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach (var modifier in this.Modifiers)
{
codeWriter
.Append(modifier)
.Append(' ');
}
codeWriter.Append(this.Type)
.Append(' ')
.Append(this.Name)
.Append(' ')
.Append('=')
.Append(' ')
.Append(this.Value)
.Append(';');
}
}
}
@@ -1,48 +0,0 @@
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class GetterTemplate : AbstractTemplate
{
public List<Modifier> Modifiers { get; } = new List<Modifier>();
public CodeTemplate Code { get; set; }
public GetterTemplate WithModifiers(params Modifier[] modifiers)
{
this.Modifiers.Clear();
this.Modifiers.AddRange(modifiers);
return this;
}
public GetterTemplate WithCode(CodeTemplate codeTemplate)
{
this.Code = codeTemplate;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach(var modifier in this.Modifiers)
{
codeWriter
.Append(modifier)
.Append(' ');
}
codeWriter.Append("get");
if (this.Code is SimpleCodeTemplate simpleGetter)
{
codeWriter
.Append(simpleGetter)
.AppendLine();
}
else
{
codeWriter
.BeginCodeBlock()
.Append(this.Code)
.EndCodeBlock();
}
}
}
}
@@ -1,72 +0,0 @@
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class MethodTemplate : AbstractTemplate
{
public List<Modifier> Modifiers { get; } = new List<Modifier>();
public List<ArgumentTemplate> Arguments { get; } = new List<ArgumentTemplate>();
public string Name { get; set; }
public string ReturnType { get; set; }
public string Body { get; set; }
public MethodTemplate WithModifiers(params Modifier[] modifiers)
{
this.Modifiers.Clear();
this.Modifiers.AddRange(modifiers);
return this;
}
public MethodTemplate WithArguments(params ArgumentTemplate[] argumentTemplates)
{
this.Arguments.Clear();
this.Arguments.AddRange(argumentTemplates);
return this;
}
public MethodTemplate WithName(string name)
{
this.Name = name;
return this;
}
public MethodTemplate WithReturnType(string returnType)
{
this.ReturnType = returnType;
return this;
}
public MethodTemplate WithBody(string body)
{
this.Body = body;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach(var modifier in this.Modifiers)
{
codeWriter
.Append(modifier)
.Append(' ');
}
codeWriter
.Append(this.ReturnType)
.Append(' ')
.Append(this.Name)
.Append('(');
for(int i = 0; i < this.Arguments.Count; i++)
{
var argument = this.Arguments[i];
codeWriter.Append(argument);
if (i < this.Arguments.Count - 1)
{
codeWriter.Append(", ");
}
}
codeWriter
.Append(')')
.BeginCodeBlock()
.Append(this.Body)
.EndCodeBlock();
}
}
}
@@ -1,57 +0,0 @@
using System.Collections;
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class Modifier : AbstractTemplate
{
public static Modifier Protected { get; } = new Modifier { Value = "protected" };
public static Modifier Readonly { get; } = new Modifier { Value = "readonly" };
public static Modifier Static { get; } = new Modifier { Value = "static" };
public static Modifier Public { get; } = new Modifier { Value = "public" };
public static Modifier Internal { get; } = new Modifier { Value = "internal" };
public static Modifier Private { get; } = new Modifier { Value = "private" };
public static Modifier Abstract { get; } = new Modifier { Value = "abstract" };
public static Modifier Virtual { get; } = new Modifier { Value = "virtual" };
public static Modifier Partial { get; } = new Modifier { Value = "partial" };
public static Modifier Sealed { get; } = new Modifier { Value = "sealed" };
public string Value { get; private set; }
private Modifier()
{
}
public override void Generate(CodeWriter codeWriter)
{
codeWriter.Append(this.Value);
}
public static bool TryParse(string value, out Modifier modifier)
{
foreach(var supportedModifier in SupportedModifiers)
{
if (supportedModifier.Value.Equals(value, StringComparison.Ordinal))
{
modifier = supportedModifier;
return true;
}
}
modifier = null;
return false;
}
public static Modifier Parse(string value)
{
if (TryParse(value, out var modifier))
{
return modifier;
}
throw new InvalidOperationException($"Could not find a modifier with value {value}");
}
private static IEnumerable<Modifier> SupportedModifiers { get; } = new List<Modifier> { Protected, Readonly, Static, Internal, Public, Private, Abstract, Virtual, Partial, Sealed };
}
}
@@ -1,19 +0,0 @@
namespace System.Extensions.Templates
{
internal sealed class NamespaceTemplate : AbstractTemplate
{
public string Namespace { get; set; }
public NamespaceTemplate WithNamespace(string n)
{
this.Namespace = n;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
codeWriter
.Append("namespace ")
.Append(this.Namespace);
}
}
}
@@ -1,67 +0,0 @@
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class PropertyTemplate : AbstractTemplate
{
public static GetterTemplate DefaultGetter = new GetterTemplate()
.WithCode(
new SimpleCodeTemplate()
.WithCode(";"));
public static SetterTemplate DefaultSetter = new SetterTemplate()
.WithCode(
new SimpleCodeTemplate()
.WithCode(";"));
public List<Modifier> Modifiers { get; private set; } = new List<Modifier>() { Modifier.Public };
public GetterTemplate Getter { get; set; } = DefaultGetter;
public SetterTemplate Setter { get; set; } = DefaultSetter;
public string Type { get; set; }
public string Name { get; set; }
public PropertyTemplate WithGetter(GetterTemplate getter)
{
this.Getter = getter;
return this;
}
public PropertyTemplate WithSetter(SetterTemplate setter)
{
this.Setter = setter;
return this;
}
public PropertyTemplate WithModifiers(params Modifier[] modifiers)
{
this.Modifiers.Clear();
this.Modifiers.AddRange(modifiers);
return this;
}
public PropertyTemplate WithName(string name)
{
this.Name = name;
return this;
}
public PropertyTemplate WithType(string type)
{
this.Type = type;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach(var modifier in this.Modifiers)
{
codeWriter
.Append(modifier)
.Append(' ');
}
codeWriter
.Append(this.Type)
.Append(' ')
.Append(this.Name)
.BeginCodeBlock()
.Append(this.Getter)
.Append(this.Setter)
.EndCodeBlock();
}
}
}
@@ -1,48 +0,0 @@
using System.Collections.Generic;
namespace System.Extensions.Templates
{
internal sealed class SetterTemplate : AbstractTemplate
{
public List<Modifier> Modifiers { get; } = new List<Modifier>();
public CodeTemplate Code { get; set; }
public SetterTemplate WithModifiers(params Modifier[] modifiers)
{
this.Modifiers.Clear();
this.Modifiers.AddRange(modifiers);
return this;
}
public SetterTemplate WithCode(CodeTemplate codeTemplate)
{
this.Code = codeTemplate;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
foreach (var modifier in this.Modifiers)
{
codeWriter
.Append(modifier)
.Append(' ');
}
codeWriter.Append("set");
if (this.Code is SimpleCodeTemplate simpleSetter)
{
codeWriter
.Append(simpleSetter)
.AppendLine();
}
else
{
codeWriter
.BeginCodeBlock()
.Append(this.Code)
.EndCodeBlock();
}
}
}
}
@@ -1,18 +0,0 @@
namespace System.Extensions.Templates
{
internal sealed class SimpleCodeTemplate : CodeTemplate
{
public string Code { get; set; }
public SimpleCodeTemplate WithCode(string code)
{
this.Code = code;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
codeWriter.Append(this.Code);
}
}
}
@@ -1,20 +0,0 @@
namespace System.Extensions.Templates
{
internal sealed class UsingsTemplate : AbstractTemplate
{
public string Namespace { get; set; }
public UsingsTemplate WithNamespace(string n)
{
this.Namespace = n;
return this;
}
public override void Generate(CodeWriter codeWriter)
{
codeWriter
.Append("using ")
.Append(this.Namespace)
.Append(';');
}
}
}
@@ -7,16 +7,20 @@
<Authors>Alexandru Macocian</Authors>
<Description>Source generator library.</Description>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Version>0.1.1</Version>
<Version>0.3.1</Version>
<LangVersion>latest</LangVersion>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all">
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" PrivateAssets="all" />
<PackageReference Include="Sybil" Version="0.8.4" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
@@ -29,6 +33,7 @@
<ItemGroup>
<!-- Package the generator in the analyzer directory of the nuget package -->
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<None Include="$(OutputPath)\Sybil.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
</Project>
@@ -0,0 +1,6 @@
namespace SystemExtensions.DependencyInjection.Tests.Configuration
{
public sealed class DummyOptions
{
}
}
@@ -1,25 +0,0 @@
using Microsoft.Extensions.Logging;
using System.Extensions;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace WpfExtended.Tests.Http
{
public class HttpMessageLogger : DelegatingHandler
{
private readonly ILogger logger;
public HttpMessageLogger(ILogger logger, HttpMessageHandler innerHandler) : base(innerHandler)
{
this.logger = logger.ThrowIfNull(nameof(logger));
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
this.logger.LogInformation($"{request.Method} - {request.RequestUri}");
var response = await base.SendAsync(request, cancellationToken);
this.logger.LogInformation($"{response.RequestMessage.RequestUri} - {response.StatusCode}");
return response;
}
}
}
-53
View File
@@ -1,53 +0,0 @@
using Microsoft.Extensions.Logging;
using Slim;
using System;
using System.Extensions;
using System.Net.Http;
using System.Windows.Extensions;
using System.Windows.Extensions.Http;
using WpfExtended.Test;
using WpfExtended.Tests.Http;
namespace WpfExtended.Tests
{
public class Launcher : ExtendedApplication<MainWindow>
{
private static Launcher Instance { get; } = new Launcher();
[STAThread]
public static int Main()
{
return Instance.Run();
}
protected override void SetupServiceManager(IServiceManager serviceManager)
{
serviceManager.RegisterDebugLoggerFactory();
serviceManager.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory((sp, category) =>
{
var loggerType = typeof(ILogger<>).MakeGenericType(category);
var logger = sp.GetService(loggerType).As<ILogger>();
return new HttpMessageLogger(logger, new HttpClientHandler());
}));
}
protected override void ApplicationClosing()
{
}
protected override void ApplicationStarting()
{
}
protected override bool HandleException(Exception e)
{
return false;
}
protected override void RegisterServices(IServiceProducer serviceProducer)
{
}
}
}
+41
View File
@@ -0,0 +1,41 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Configuration;
using System.Extensions;
using SystemExtensions.DependencyInjection.Tests.Configuration;
namespace WpfExtended.Tests.Services
{
public sealed class DummyService : IDummyService
{
private readonly ILogger<DummyService> logger;
private readonly IOptions<DummyOptions> dummyOptions;
private readonly IUpdateableOptions<DummyOptions> updateableDummyOptions;
private readonly ILiveOptions<DummyOptions> liveOptions;
private readonly ILiveUpdateableOptions<DummyOptions> liveUpdateableOptions;
public DummyService(
ILogger<DummyService> logger,
IOptions<DummyOptions> options,
IUpdateableOptions<DummyOptions> updateableOptions,
ILiveUpdateableOptions<DummyOptions> liveUpdateableOptions,
ILiveOptions<DummyOptions> liveOptions)
{
this.logger = logger.ThrowIfNull(nameof(logger));
this.dummyOptions = options.ThrowIfNull(nameof(options));
this.updateableDummyOptions = updateableOptions.ThrowIfNull(nameof(updateableOptions));
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
this.liveUpdateableOptions = liveUpdateableOptions.ThrowIfNull(nameof(liveUpdateableOptions));
}
public void OnClosing()
{
this.logger.LogInformation($"Closing {nameof(DummyService)}");
}
public void OnStartup()
{
this.logger.LogInformation($"Starting {nameof(DummyService)}");
}
}
}
@@ -0,0 +1,8 @@
using System.Windows.Extensions.Services;
namespace WpfExtended.Tests.Services
{
public interface IDummyService : IApplicationLifetimeService
{
}
}
@@ -0,0 +1,23 @@
<UserControl x:Class="WpfExtended.Tests.TestApplication.Controls.PropertyList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfExtended.Tests.TestApplication.Controls"
DataContextChanged="PropertyList_DataContextChanged"
mc:Ignorable="d"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ListView ItemsSource="{Binding ElementName=_this, Path=EffectProperties, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBox Text="{Binding Value, Mode=OneWay}" KeyDown="TextBox_KeyDown"></TextBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
@@ -0,0 +1,67 @@
using System.Collections.ObjectModel;
using System.Extensions;
using System.Linq;
using System.Threading;
using System.Windows.Controls;
using System.Windows.Media.Effects;
using WpfExtended.Tests.TestApplication.Models;
namespace WpfExtended.Tests.TestApplication.Controls
{
/// <summary>
/// Interaction logic for PropertyList.xaml
/// </summary>
public partial class PropertyList : UserControl
{
public ObservableCollection<EffectProperty> EffectProperties { get; } = new ObservableCollection<EffectProperty>();
public PropertyList()
{
this.InitializeComponent();
}
private void PropertyList_DataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
if (this.DataContext is not ShaderEffect shaderEffect)
{
return;
}
this.EffectProperties.ClearAnd().AddRange(shaderEffect.GetType().GetProperties()
.Where(pInfo => pInfo.PropertyType == typeof(double))
.Select(pInfo => new EffectProperty
{
Name = pInfo.Name,
Property = pInfo,
Value = (double)pInfo.GetValue(shaderEffect),
Source = shaderEffect
}));
}
private void TextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (sender is not TextBox textBox)
{
return;
}
if (textBox.DataContext is not EffectProperty effectProperty)
{
return;
}
if (e.Key is not System.Windows.Input.Key.Enter)
{
return;
}
if (!double.TryParse(textBox.Text, out var value))
{
return;
}
effectProperty.Value = value;
effectProperty.UpdateProperty();
}
}
}
@@ -0,0 +1,55 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Logging;
using Microsoft.Extensions.Logging;
using Slim;
using Slim.Integration.ServiceCollection;
using System;
using System.Extensions;
using System.Logging;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Extensions;
using WpfExtended.Test;
using WpfExtended.Tests.Services;
namespace WpfExtended.Tests
{
public class Launcher : ExtendedApplication<MainWindow>
{
private static Launcher Instance { get; } = new Launcher();
[STAThread]
public static void Main()
{
Instance.Run();
}
protected override System.IServiceProvider SetupServiceProvider(IServiceCollection services)
{
var serviceManager = new ServiceManager();
serviceManager.RegisterResolver(new LoggerResolver());
serviceManager.RegisterDebugLoggerFactory();
serviceManager.RegisterOptionsManager();
services.RegisterHttpClient<MainWindow>()
.Build();
var provider = services.BuildSlimServiceProvider(serviceManager);
return provider;
}
protected override void ApplicationClosing()
{
}
protected override ValueTask ApplicationStarting() => ValueTask.CompletedTask;
protected override bool HandleException(Exception e)
{
return false;
}
protected override void RegisterServices(IServiceCollection services)
{
services.AddSingleton<IDummyService, DummyService>();
}
}
}
@@ -4,11 +4,19 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfExtended.Test"
xmlns:controls="clr-namespace:WpfExtended.Tests.TestApplication.Controls"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<ScrollViewer>
<WrapPanel x:Name="WrapPanel" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></WrapPanel>
</ScrollViewer>
<ScrollViewer Grid.Column="1">
<controls:PropertyList x:Name="PropertyList"></controls:PropertyList>
</ScrollViewer>
</Grid>
</Window>
@@ -1,8 +1,8 @@
using Microsoft.Extensions.Logging;
using System;
using System.Extensions;
using System.Http;
using System.IO;
using System.Net.Http;
using System.Windows;
using System.Windows.Extensions;
using System.Windows.Media;
@@ -64,8 +64,21 @@ namespace WpfExtended.Test
BorderBrush = Brushes.LightGray,
BorderThickness = new Thickness(1)
};
image.MouseLeftButtonDown += Image_MouseLeftButtonDown;
this.WrapPanel.Children.Add(image);
}
}
private void Image_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (sender is not CaptionedImage captionedImage)
{
return;
}
var effect = captionedImage.ImageEffect;
this.PropertyList.DataContext = effect;
}
}
}
@@ -0,0 +1,27 @@
using System.Reflection;
namespace WpfExtended.Tests.TestApplication.Models
{
public sealed class EffectProperty
{
public string Name { get; set; }
public double Value { get; set; }
public object Source { get; set; }
public PropertyInfo Property { get; set; }
public void UpdateProperty()
{
if (this.Source is null)
{
return;
}
if (this.Property is null)
{
return;
}
this.Property.SetValue(this.Source, this.Value);
}
}
}
+12 -3
View File
@@ -1,13 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<OutputType>Library</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<StartupObject>WpfExtended.Tests.Launcher</StartupObject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
<PackageReference Include="FlaUI.UIA3" Version="5.0.0" />
<PackageReference Include="FluentAssertions" Version="8.8.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Microsoft.TestPlatform" Version="18.0.1" />
<PackageReference Include="Microsoft.TestPlatform.TestHost" Version="18.0.1" />
<PackageReference Include="MSTest.TestAdapter" Version="4.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="4.0.2" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.6.12" />
</ItemGroup>
<ItemGroup>
-43
View File
@@ -1,43 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfExtended", "WpfExtended\WpfExtended.csproj", "{E822AE0D-5EA1-4C61-A1DC-76CF73C8A524}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfExtended.Tests", "WpfExtended.Test\WpfExtended.Tests.csproj", "{48D2B8E6-F906-40D8-952E-B7B567D76A9B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfExtended.SourceGeneration", "WpfExtended.SourceGeneration\WpfExtended.SourceGeneration.csproj", "{BB890187-DF49-4E58-AE41-09C40F541292}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfExtended.SourceGeneration.Tests", "WpfExtended.SourceGeneration.Tests\WpfExtended.SourceGeneration.Tests.csproj", "{BDD41E4C-3F5D-4734-8BD2-62B444E4845D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E822AE0D-5EA1-4C61-A1DC-76CF73C8A524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E822AE0D-5EA1-4C61-A1DC-76CF73C8A524}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E822AE0D-5EA1-4C61-A1DC-76CF73C8A524}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E822AE0D-5EA1-4C61-A1DC-76CF73C8A524}.Release|Any CPU.Build.0 = Release|Any CPU
{48D2B8E6-F906-40D8-952E-B7B567D76A9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48D2B8E6-F906-40D8-952E-B7B567D76A9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48D2B8E6-F906-40D8-952E-B7B567D76A9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48D2B8E6-F906-40D8-952E-B7B567D76A9B}.Release|Any CPU.Build.0 = Release|Any CPU
{BB890187-DF49-4E58-AE41-09C40F541292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB890187-DF49-4E58-AE41-09C40F541292}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB890187-DF49-4E58-AE41-09C40F541292}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB890187-DF49-4E58-AE41-09C40F541292}.Release|Any CPU.Build.0 = Release|Any CPU
{BDD41E4C-3F5D-4734-8BD2-62B444E4845D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDD41E4C-3F5D-4734-8BD2-62B444E4845D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDD41E4C-3F5D-4734-8BD2-62B444E4845D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDD41E4C-3F5D-4734-8BD2-62B444E4845D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DE159EB4-7D6E-46D0-9366-391E9FDD37DC}
EndGlobalSection
EndGlobal
+10
View File
@@ -0,0 +1,10 @@
<Solution>
<Folder Name="/Solution Items/">
<File Path=".github/workflows/cd.yaml" />
<File Path=".github/workflows/ci.yaml" />
</Folder>
<Project Path="WpfExtended.Blazor/WpfExtended.Blazor.csproj" />
<Project Path="WpfExtended.SourceGeneration/WpfExtended.SourceGeneration.csproj" />
<Project Path="WpfExtended.Test/WpfExtended.Tests.csproj" />
<Project Path="WpfExtended/WpfExtended.csproj" />
</Solution>
@@ -0,0 +1,80 @@
using System.Windows.Media.Effects;
namespace System.Windows.Media.Extensions.Effects
{
#if SILVERLIGHT
using UIPropertyMetadata = System.Windows.PropertyMetadata ;
#endif
/// <summary>
/// Combines Embossed effect with a noise effect to distort an image based on the depth of the image contents
/// </summary>
public class DepthBlur : ShaderEffect
{
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(DepthBlur), 0, SamplingMode.Bilinear);
public static readonly DependencyProperty FocusDepthProperty = DependencyProperty.Register("FocusDepth", typeof(double), typeof(DepthBlur), new UIPropertyMetadata(0.5, PixelShaderConstantCallback(0)));
public static readonly DependencyProperty FocusRangeProperty = DependencyProperty.Register("FocusStrength", typeof(double), typeof(DepthBlur), new UIPropertyMetadata(0.2, PixelShaderConstantCallback(1)));
public static readonly DependencyProperty TextureWidthProperty = DependencyProperty.Register("TextureWidth", typeof(double), typeof(DepthBlur), new UIPropertyMetadata(512d, PixelShaderConstantCallback(2)));
public static readonly DependencyProperty TextureHeightProperty = DependencyProperty.Register("TextureHeight", typeof(double), typeof(DepthBlur), new UIPropertyMetadata(512d, PixelShaderConstantCallback(3)));
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(double), typeof(DepthBlur), new UIPropertyMetadata(0d, PixelShaderConstantCallback(4)));
public static readonly DependencyProperty StrengthProperty = DependencyProperty.Register("Strength", typeof(double), typeof(DepthBlur), new UIPropertyMetadata(1d, PixelShaderConstantCallback(5)));
private readonly static PixelShader pixelShader = new PixelShader();
static DepthBlur()
{
pixelShader = PixelShaderUtility.LoadPixelShader<DepthBlur>();
}
public DepthBlur()
{
this.PixelShader = pixelShader;
// Update each DependencyProperty that's registered with a shader register. This
// is needed to ensure the shader gets sent the proper default value.
UpdateShaderValue(InputProperty);
UpdateShaderValue(FocusDepthProperty);
UpdateShaderValue(FocusRangeProperty);
UpdateShaderValue(TextureWidthProperty);
UpdateShaderValue(TextureHeightProperty);
UpdateShaderValue(AngleProperty);
UpdateShaderValue(StrengthProperty);
}
[System.ComponentModel.BrowsableAttribute(false)]
public Brush Input
{
get { return (Brush)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public double FocusDepth
{
get { return (double)GetValue(FocusDepthProperty); }
set { SetValue(FocusDepthProperty, value); }
}
public double FocusRange
{
get { return (double)GetValue(FocusRangeProperty); }
set { SetValue(FocusRangeProperty, value); }
}
public double TextureWidth
{
get { return (double)GetValue(TextureWidthProperty); }
set { SetValue(TextureWidthProperty, value); }
}
public double TextureHeight
{
get { return (double)GetValue(TextureHeightProperty); }
set { SetValue(TextureHeightProperty, value); }
}
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
public double Strength
{
get { return (double)GetValue(StrengthProperty); }
set { SetValue(StrengthProperty, value); }
}
}
}
@@ -0,0 +1,55 @@
//-----------------------------------------------------------------------------------------
// Shader constant register mappings (scalars - float, double, Point, Color, Point3D, etc.)
//-----------------------------------------------------------------------------------------
float FocusDepth : register(C0);
float FocusRange : register(C1);
float TextureWidth : register(C2);
float TextureHeight : register(C3);
float Strength : register(C5);
//--------------------------------------------------------------------------------------
// Sampler Inputs (Brushes, including ImplicitInput)
//--------------------------------------------------------------------------------------
sampler2D implicitInputSampler : register(S0);
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 originalColor = tex2D(implicitInputSampler, uv);
// Compute the luminance
float luminance = 0.299f * originalColor.r + 0.587f * originalColor.g + 0.114f * originalColor.b;
// Calculate the blur amount based on the luminance
float blurAmount = abs(luminance - FocusDepth) - FocusRange;
blurAmount = clamp(blurAmount, 0.0f, 1.0f);
float2 texelSize = 1.0f / float2(TextureWidth, TextureHeight); // Assuming a texture resolution of 512x512. Change as necessary.
float4 color = float4(0, 0, 0, 0);
float blurSize = 5;
// Simple box blur
for (int i = -blurSize; i <= blurSize; i++)
{
for (int j = -blurSize; j <= blurSize; j++)
{
color += tex2D(implicitInputSampler, uv + blurAmount * float2(i, j) * texelSize);
}
}
color /= (2 * blurSize + 1) * (2 * blurSize + 1);
// Set the pixel colors as a multiple of the luminance
color.rgb = luminance * color.rgb;
// Preserve the original alpha
color.a = originalColor.a;
return color;
}
Binary file not shown.
+64
View File
@@ -0,0 +1,64 @@
using System.Windows.Media.Effects;
namespace System.Windows.Media.Extensions.Effects
{
#if SILVERLIGHT
using UIPropertyMetadata = System.Windows.PropertyMetadata ;
#endif
public class Impasto : ShaderEffect
{
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(Impasto), 0);
public static readonly DependencyProperty TexelWidthProperty = DependencyProperty.Register("TexelWidth", typeof(double), typeof(Impasto), new UIPropertyMetadata(512d, PixelShaderConstantCallback(0)));
public static readonly DependencyProperty TexelHeightProperty = DependencyProperty.Register("TexelHeight", typeof(double), typeof(Impasto), new UIPropertyMetadata(512d, PixelShaderConstantCallback(1)));
public static readonly DependencyProperty StrengthProperty = DependencyProperty.Register("Strength", typeof(double), typeof(Impasto), new UIPropertyMetadata(15d, PixelShaderConstantCallback(2)));
public static readonly DependencyProperty DepthProperty = DependencyProperty.Register("Depth", typeof(double), typeof(Impasto), new UIPropertyMetadata(100d, PixelShaderConstantCallback(3)));
private readonly static PixelShader pixelShader;
static Impasto()
{
pixelShader = PixelShaderUtility.LoadPixelShader<Impasto>();
}
public Impasto()
{
this.PixelShader = pixelShader;
UpdateShaderValue(InputProperty);
UpdateShaderValue(TexelWidthProperty);
UpdateShaderValue(TexelHeightProperty);
UpdateShaderValue(StrengthProperty);
UpdateShaderValue(DepthProperty);
}
[System.ComponentModel.BrowsableAttribute(false)]
public Brush Input
{
get { return (Brush)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public double TexelWidth
{
get { return (double)GetValue(TexelWidthProperty); }
set { SetValue(TexelWidthProperty, value); }
}
public double TexelHeight
{
get { return (double)GetValue(TexelHeightProperty); }
set { SetValue(TexelHeightProperty, value); }
}
public double Strength
{
get { return (double)GetValue(StrengthProperty); }
set { SetValue(StrengthProperty, value); }
}
public double Depth
{
get { return (double)GetValue(DepthProperty); }
set { SetValue(DepthProperty, value); }
}
}
}
+64
View File
@@ -0,0 +1,64 @@
//-----------------------------------------------------------------------------------------
// Shader constant register mappings (scalars - float, double, Point, Color, Point3D, etc.)
//-----------------------------------------------------------------------------------------
float textureWidth : register(C0);
float textureHeight : register(C1);
float strength : register(C2);
float depth : register(C3);
//--------------------------------------------------------------------------------------
// Sampler Inputs (Brushes, including ImplicitInput)
//--------------------------------------------------------------------------------------
sampler2D implicitInputSampler : register(S0);
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 lightDirection = float4(0.5, 0.21, 0.85, 1);
float emboss(float2 uv)
{
float4 outC = { 0.5, 0.5, 0.5, 1.0 };
outC -= tex2D(implicitInputSampler, uv - (1 / depth)) * strength;
outC += tex2D(implicitInputSampler, uv + (1 / depth)) * strength;
outC.rgb = (outC.r + outC.g + outC.b) / 3.0f;
return outC;
}
float4 main(float2 uv : TEXCOORD) : COLOR
{
// Sample the color
float4 color = tex2D(implicitInputSampler, uv);
float2 resolution = float2(textureWidth, textureHeight);
// Use the emboss value of the color as the bump value
float bumpValue = emboss(uv);
// Calculate a basic normal based on the bump value
float2 offset = 1.0 / resolution;
float left = emboss(uv - float2(offset.x, 0));
float right = emboss(uv + float2(offset.x, 0));
float top = emboss(uv - float2(0, offset.y));
float bottom = emboss(uv + float2(0, offset.y));
float3 normal;
normal.x = (left - right) * 0.5; // Multiplier to increase the effect, tweak as necessary
normal.y = (top - bottom) * 0.5; // Same as above
normal.z = 0.5;
normal = normalize(normal);
// Compute Lambertian lighting based on the normal
float lightIntensity = dot(normal, lightDirection.xyz);
float4 invertedColor = 1 - color;
invertedColor.a = 1;
color.rgb = (invertedColor.rgb * lightIntensity * 2) + color.rgb;
return color;
}
Binary file not shown.
+50
View File
@@ -0,0 +1,50 @@
using System.Windows.Media.Effects;
using System.Windows.Threading;
namespace System.Windows.Media.Extensions.Effects
{
#if SILVERLIGHT
using UIPropertyMetadata = System.Windows.PropertyMetadata ;
#endif
public class Noise : ShaderEffect
{
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(Noise), 0);
public static readonly DependencyProperty TimeProperty = DependencyProperty.Register("Time", typeof(double), typeof(Noise), new UIPropertyMetadata(1d, PixelShaderConstantCallback(0)));
public static readonly DependencyProperty StrengthProperty = DependencyProperty.Register("Strength", typeof(double), typeof(Noise), new UIPropertyMetadata(0.01d, PixelShaderConstantCallback(1)));
private readonly static PixelShader pixelShader = new PixelShader();
static Noise()
{
pixelShader = PixelShaderUtility.LoadPixelShader<Noise>();
}
public Noise()
{
this.PixelShader = pixelShader;
// Update each DependencyProperty that's registered with a shader register. This
// is needed to ensure the shader gets sent the proper default value.
UpdateShaderValue(InputProperty);
UpdateShaderValue(TimeProperty);
UpdateShaderValue(StrengthProperty);
}
[System.ComponentModel.BrowsableAttribute(false)]
public Brush Input
{
get { return (Brush)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public double Time
{
get { return (double)GetValue(TimeProperty); }
set { SetValue(TimeProperty, value); }
}
public double Strength
{
get { return (double)GetValue(StrengthProperty); }
set { SetValue(StrengthProperty, value); }
}
}
}
+114
View File
@@ -0,0 +1,114 @@
//-----------------------------------------------------------------------------------------
// Shader constant register mappings (scalars - float, double, Point, Color, Point3D, etc.)
//-----------------------------------------------------------------------------------------
float Time : register(C0);
float Strength : register(C1);
//--------------------------------------------------------------------------------------
// Sampler Inputs (Brushes, including ImplicitInput)
//--------------------------------------------------------------------------------------
sampler2D implicitInputSampler : register(S0);
//--------------------------------------------------------------------------------------
// Cellular Noise
//--------------------------------------------------------------------------------------
//
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20201014 (stegu)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
//
// Description : Array and textureless GLSL 2D simplex noise function.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
float3 mod289(float3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
float2 mod289(float2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
float3 permute(float3 x) {
return mod289(((x*34.0)+10.0)*x);
}
float snoise(float2 v)
{
const float4 C = float4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
float2 i = floor(v + dot(v, C.yy) );
float2 x0 = v - i + dot(i, C.xx);
// Other corners
float2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? float2(1.0, 0.0) : float2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
float4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
float3 p = permute( permute( i.y + float3(0.0, i1.y, 1.0 ))
+ i.x + float3(0.0, i1.x, 1.0 ));
float3 m = max(0.5 - float3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
float3 x = 2.0 * frac(p * C.www) - 1.0;
float3 h = abs(x) - 0.5;
float3 ox = floor(x + 0.5);
float3 a0 = x - ox;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
float3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 main(float2 uv : TEXCOORD) : COLOR
{
// Compute the noise value at the pixel position and time.
float noise = snoise(uv * Time);
// Offset the UV coordinates by the noise value scaled by the distortion strength.
float2 offset = noise * Strength;
return tex2D(implicitInputSampler, uv + offset);
}
Binary file not shown.
+81
View File
@@ -0,0 +1,81 @@
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
using System.Windows.Media.Effects;
namespace System.Windows.Media.Extensions.Effects
{
#if SILVERLIGHT
using UIPropertyMetadata = System.Windows.PropertyMetadata ;
#endif
public class Snowfall : ShaderEffect
{
public static readonly DependencyProperty InputProperty =
ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(Snowfall), 0);
public static readonly DependencyProperty SpeedProperty =
DependencyProperty.Register("Speed", typeof(double), typeof(Snowfall), new UIPropertyMetadata(0.25, PixelShaderConstantCallback(0)));
public static readonly DependencyProperty WindStrengthProperty =
DependencyProperty.Register("WindStrength", typeof(double), typeof(Snowfall), new UIPropertyMetadata(0.2, PixelShaderConstantCallback(1)));
public static readonly DependencyProperty FlakeSizeProperty =
DependencyProperty.Register("FlakeSize", typeof(double), typeof(Snowfall), new UIPropertyMetadata(300.0, PixelShaderConstantCallback(2)));
public static readonly DependencyProperty TimeProperty =
DependencyProperty.Register("Time", typeof(double), typeof(Snowfall), new UIPropertyMetadata(0.0, PixelShaderConstantCallback(3)));
public static readonly DependencyProperty ThresholdProperty =
DependencyProperty.Register("Threshold", typeof(double), typeof(Snowfall), new UIPropertyMetadata(0.77, PixelShaderConstantCallback(4)));
private readonly static PixelShader pixelShader = new();
static Snowfall()
{
pixelShader = PixelShaderUtility.LoadPixelShader<Snowfall>();
}
public Snowfall()
{
this.PixelShader = pixelShader;
// Update each DependencyProperty that's registered with a shader register. This
// is needed to ensure the shader gets sent the proper default value.
UpdateShaderValue(InputProperty);
UpdateShaderValue(SpeedProperty);
UpdateShaderValue(WindStrengthProperty);
UpdateShaderValue(FlakeSizeProperty);
UpdateShaderValue(TimeProperty);
UpdateShaderValue(ThresholdProperty);
}
[System.ComponentModel.BrowsableAttribute(false)]
public Brush Input
{
get { return (Brush)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public double Speed
{
get { return (double)GetValue(SpeedProperty); }
set { SetValue(SpeedProperty, value); }
}
public double WindStrength
{
get { return (double)GetValue(WindStrengthProperty); }
set { SetValue(WindStrengthProperty, value); }
}
public double FlakeSize
{
get { return (double)GetValue(FlakeSizeProperty); }
set { SetValue(FlakeSizeProperty, value); }
}
public double Time
{
get { return (double)GetValue(TimeProperty); }
set { SetValue(TimeProperty, value); }
}
public double Threshold
{
get { return (double)GetValue(ThresholdProperty); }
set { SetValue(ThresholdProperty, value); }
}
}
}
+153
View File
@@ -0,0 +1,153 @@
//-----------------------------------------------------------------------------------------
// Shader constant register mappings (scalars - float, double, Point, Color, Point3D, etc.)
//-----------------------------------------------------------------------------------------
float Speed : register(C0);
float WindStrength : register(C1);
float FlakeSize : register(C2);
float Time : register(C3);
float Threshold : register(C4);
//--------------------------------------------------------------------------------------
// Sampler Inputs (Brushes, including ImplicitInput)
//--------------------------------------------------------------------------------------
sampler2D implicitInputSampler : register(S0);
//--------------------------------------------------------------------------------------
// https://github.com/keijiro/NoiseShader/tree/master/Packages/jp.keijiro.noiseshader/Shader
//--------------------------------------------------------------------------------------
float wglnoise_mod(float x, float y)
{
return x - y * floor(x / y);
}
float2 wglnoise_mod(float2 x, float2 y)
{
return x - y * floor(x / y);
}
float3 wglnoise_mod(float3 x, float3 y)
{
return x - y * floor(x / y);
}
float4 wglnoise_mod(float4 x, float4 y)
{
return x - y * floor(x / y);
}
float2 wglnoise_fade(float2 t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
float3 wglnoise_fade(float3 t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
float wglnoise_mod289(float x)
{
return x - floor(x / 289) * 289;
}
float2 wglnoise_mod289(float2 x)
{
return x - floor(x / 289) * 289;
}
float3 wglnoise_mod289(float3 x)
{
return x - floor(x / 289) * 289;
}
float4 wglnoise_mod289(float4 x)
{
return x - floor(x / 289) * 289;
}
float3 wglnoise_permute(float3 x)
{
return wglnoise_mod289((x * 34 + 1) * x);
}
float4 wglnoise_permute(float4 x)
{
return wglnoise_mod289((x * 34 + 1) * x);
}
float3 SimplexNoiseGrad(float2 v)
{
const float C1 = (3 - sqrt(3)) / 6;
const float C2 = (sqrt(3) - 1) / 2;
// First corner
float2 i = floor(v + dot(v, C2));
float2 x0 = v - i + dot(i, C1);
// Other corners
float2 i1 = x0.x > x0.y ? float2(1, 0) : float2(0, 1);
float2 x1 = x0 + C1 - i1;
float2 x2 = x0 + C1 * 2 - 1;
// Permutations
i = wglnoise_mod289(i); // Avoid truncation effects in permutation
float3 p = wglnoise_permute(i.y + float3(0, i1.y, 1));
p = wglnoise_permute(p + i.x + float3(0, i1.x, 1));
// Gradients: 41 points uniformly over a unit circle.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
float3 phi = p / 41 * 3.14159265359 * 2;
float2 g0 = float2(cos(phi.x), sin(phi.x));
float2 g1 = float2(cos(phi.y), sin(phi.y));
float2 g2 = float2(cos(phi.z), sin(phi.z));
// Compute noise and gradient at P
float3 m = float3(dot(x0, x0), dot(x1, x1), dot(x2, x2));
float3 px = float3(dot(g0, x0), dot(g1, x1), dot(g2, x2));
m = max(0.5 - m, 0);
float3 m3 = m * m * m;
float3 m4 = m * m3;
float3 temp = -8 * m3 * px;
float2 grad = m4.x * g0 + temp.x * x0 +
m4.y * g1 + temp.y * x1 +
m4.z * g2 + temp.z * x2;
return 99.2 * float3(grad, dot(m4, px));
}
float SimplexNoise(float2 v)
{
return SimplexNoiseGrad(v).z;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 color = tex2D(implicitInputSampler, uv);
// Calculate a parallax offset based on depth. Here, we just use the Y coordinate
uv.y -= Time * Speed;
uv.x += WindStrength * Time;
// Get the random value to decide where to place a snowflake
float randVal = (SimplexNoise(uv * FlakeSize) + 1) / 2;
//float randVal = (snoise(floor(tiledUV)) + 1) / 2;
// Generate a dynamic circular snowflake if within the threshold
if (randVal > Threshold)
{
color.rgb = lerp(color.rgb, float3(1, 1, 1), 0.5 + (randVal - Threshold) / (1 - Threshold));
}
return color;
}
Binary file not shown.
@@ -1,84 +0,0 @@
using Microsoft.Extensions.Logging;
using Slim;
using System.Extensions;
using System.Net.Http;
using System.Windows.Extensions.Http;
using WpfExtended.Logging;
namespace System.Windows.Extensions
{
public static class ServiceManagerExtensions
{
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="ServiceManager"/>.</param>
/// <returns>Provided <see cref="ServiceManager"/>.</returns>
public static IServiceProducer RegisterLogWriter<TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : ILogsWriter
{
serviceManager.RegisterSingleton<ILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return factory;
});
return serviceManager;
}
/// <summary>
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
/// </summary>
/// <typeparam name="TILogsWriter">Interface of <see cref="ILogsWriter"/>.</typeparam>
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
/// <param name="serviceManager"><see cref="ServiceManager"/>.</param>
/// <returns>Provided <see cref="ServiceManager"/>.</returns>
public static IServiceProducer RegisterLogWriter<TILogsWriter, TLogsWriter>(this IServiceProducer serviceManager)
where TLogsWriter : TILogsWriter
where TILogsWriter : class, ILogsWriter
{
serviceManager.RegisterSingleton<TILogsWriter, TLogsWriter>();
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
var factory = new LoggerFactory();
factory.AddProvider(new CVLoggerProvider(sp.GetService<TILogsWriter>()));
return factory;
});
return serviceManager;
}
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
{
serviceManager.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
return serviceManager;
}
public static IServiceManager RegisterDebugLoggerFactory(this IServiceManager serviceManager)
{
serviceManager.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
return serviceManager;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterResolver(new HttpClientResolver());
return serviceManager;
}
public static IServiceManager RegisterHttpFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, Type, HttpMessageHandler> handlerFactory)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
serviceManager.RegisterResolver(
new HttpClientResolver()
.WithHttpMessageHandlerFactory(handlerFactory));
return serviceManager;
}
}
}
-53
View File
@@ -1,53 +0,0 @@
using Microsoft.Extensions.Logging;
using Slim.Resolvers;
using System.Extensions;
using System.Http;
using System.Linq;
using System.Net.Http;
namespace System.Windows.Extensions.Http
{
public sealed class HttpClientResolver : IDependencyResolver
{
private static readonly Type clientType = typeof(HttpClient<>);
private static readonly Type loggerType = typeof(ILogger<>);
/// <summary>
/// Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.
/// </summary>
public Func<Slim.IServiceProvider, Type, HttpMessageHandler> HttpMessageHandlerFactory { get; set; }
/// <summary>
/// Sets the <see cref="HttpMessageHandlerFactory"/>.
/// </summary>
/// <param name="factory">Factory method. <see cref="Type"/> parameter of the factory is the scope of <see cref="IHttpClient{TScope}"/>.</param>
/// <returns></returns>
public HttpClientResolver WithHttpMessageHandlerFactory(Func<Slim.IServiceProvider, Type, HttpMessageHandler> factory)
{
this.HttpMessageHandlerFactory = factory;
return this;
}
public bool CanResolve(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IHttpClient<>))
{
return true;
}
return false;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
var typedClientType = clientType.MakeGenericType(type.GetGenericArguments());
var typedLoggerType = loggerType.MakeGenericType(type.GetGenericArguments());
var logger = serviceProvider.GetService(typedLoggerType).As<ILogger>();
var handler = this.HttpMessageHandlerFactory?.Invoke(serviceProvider, type.GetGenericArguments().First());
var httpClient = handler is null ?
Activator.CreateInstance(typedClientType) :
Activator.CreateInstance(typedClientType, new object[] { handler });
return httpClient;
}
}
}
+44 -23
View File
@@ -1,9 +1,10 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Debug;
using Microsoft.Extensions.DependencyInjection;
using Slim;
using Slim.Integration.ServiceCollection;
using System.Extensions;
using System.Logging;
using System.Threading.Tasks;
using System.Windows.Extensions.Logging;
using System.Windows.Extensions.Services;
namespace System.Windows.Extensions
{
@@ -14,36 +15,44 @@ namespace System.Windows.Extensions
public abstract class ExtendedApplication<T> : Application
where T : Window
{
protected IServiceManager ServiceManager { get; } = new ServiceManager();
protected ILoggerFactory LoggerFactory { get; private set; }
private readonly ServiceCollection services = new();
protected IServiceProvider ServiceProvider { get; private set; }
protected virtual bool ShowWindowOnStartup { get; set; } = true;
public ExtendedApplication()
{
this.RegisterInternals();
}
/// <summary>
/// Do some work on the <see cref="IServiceManager"/> before calling <see cref="RegisterServices(IServiceProducer)"/>.
/// Create a new <see cref="IServiceProvider"/>.
/// </summary>
protected virtual void SetupServiceManager(IServiceManager serviceManager)
protected virtual IServiceProvider SetupServiceProvider(IServiceCollection services)
{
serviceManager.RegisterDebugLoggerFactory();
serviceManager.RegisterHttpFactory();
var serviceProvider = services.BuildSlimServiceProvider();
if (serviceProvider is IServiceManager serviceManager)
{
serviceManager.RegisterDebugLoggerFactory();
serviceManager.RegisterHttpFactory();
serviceManager.RegisterResolver(new LoggerResolver());
}
return serviceProvider;
}
/// <summary>
/// Called right before the window is shown.
/// </summary>
protected abstract void ApplicationStarting();
protected abstract ValueTask ApplicationStarting();
/// <summary>
/// Called right before the application is closing.
/// </summary>
protected abstract void ApplicationClosing();
/// <summary>
/// Register services into the <see cref="IServiceProducer"/>.
/// Register services into the <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="serviceProducer"></param>
protected abstract void RegisterServices(IServiceProducer serviceProducer);
/// <param name="serviceCollection"></param>
protected abstract void RegisterServices(IServiceCollection services);
/// <summary>
/// Handle a caught exception.
/// </summary>
@@ -54,14 +63,20 @@ namespace System.Windows.Extensions
protected sealed override void OnStartup(StartupEventArgs e)
{
this.SetupExceptionHandling();
this.SetupServiceManager(this.ServiceManager);
this.RegisterServices(this.ServiceManager);
this.RegisterInternals();
this.RegisterServices(this.services);
this.ServiceProvider = this.SetupServiceProvider(this.services);
this.SetupApplicationLifetime();
this.LaunchWindow();
}
protected sealed override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
foreach (var service in this.ServiceProvider.GetServices<IApplicationLifetimeService>())
{
service?.OnClosing();
}
this.ApplicationClosing();
}
protected sealed override void OnSessionEnding(SessionEndingCancelEventArgs e)
@@ -70,17 +85,23 @@ namespace System.Windows.Extensions
this.ApplicationClosing();
}
private void LaunchWindow()
private async void LaunchWindow()
{
var window = this.ServiceManager.GetService<T>();
this.ApplicationStarting();
window.Show();
await this.ApplicationStarting().ConfigureAwait(true);
foreach(var service in this.ServiceProvider.GetServices<IApplicationLifetimeService>())
{
service.OnStartup();
}
if (this.ShowWindowOnStartup)
{
var window = this.ServiceProvider.GetRequiredService<T>();
window.Show();
}
}
private void RegisterInternals()
{
this.ServiceManager.RegisterServiceManager();
this.ServiceManager.RegisterSingleton<T, T>();
this.ServiceManager.RegisterResolver(new LoggerResolver());
this.services.AddSingleton<T, T>();
}
private void SetupExceptionHandling()
{
-8
View File
@@ -1,8 +0,0 @@
The MIT License (MIT)
Copyright © 2021 Alexandru Macocian
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-46
View File
@@ -1,46 +0,0 @@
using Microsoft.Extensions.Logging;
using System;
using System.Extensions;
using WpfExtended.Models;
namespace WpfExtended.Logging
{
public sealed class CVLogger : ILogger
{
private readonly string category;
private readonly CVLoggerProvider cvLoggerProvider;
public CVLogger(string category, CVLoggerProvider debugLoggerProvider)
{
this.category = category;
this.cvLoggerProvider = debugLoggerProvider.ThrowIfNull(nameof(debugLoggerProvider));
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var message = formatter(state, exception);
var log = new Log
{
Exception = exception,
LogLevel = logLevel,
EventId = eventId.Name,
Message = message,
Category = category,
LogTime = DateTime.Now
};
this.cvLoggerProvider.LogEntry(log);
}
}
}
-45
View File
@@ -1,45 +0,0 @@
using Microsoft.CorrelationVector;
using Microsoft.Extensions.Logging;
using System.Extensions;
using WpfExtended.Models;
namespace WpfExtended.Logging
{
public sealed class CVLoggerProvider : ILoggerProvider
{
private readonly ILogsWriter logsManager;
private CorrelationVector correlationVector;
public CVLoggerProvider(ILogsWriter logsWriter)
{
this.logsManager = logsWriter.ThrowIfNull(nameof(logsWriter));
this.correlationVector = new CorrelationVector();
}
public void LogEntry(Log log)
{
if (this.correlationVector is not null)
{
log.CorrelationVector = this.correlationVector.Value.ToString();
this.correlationVector.Increment();
}
this.logsManager.WriteLog(log);
}
public ILogger CreateLogger(string categoryName)
{
if (this.correlationVector is not null)
{
this.correlationVector = CorrelationVector.Extend(this.correlationVector.ToString());
}
return new CVLogger(categoryName, this);
}
public void Dispose()
{
throw new System.NotImplementedException();
}
}
}
-14
View File
@@ -1,14 +0,0 @@
using System;
using System.Diagnostics;
using WpfExtended.Models;
namespace WpfExtended.Logging
{
public sealed class DebugLogsWriter : ILogsWriter
{
public void WriteLog(Log log)
{
Debug.WriteLine($"{log.LogTime} - {log.Category} - {log.EventId} - {log.CorrelationVector} - {log.LogLevel} - {log.Message}{Environment.NewLine}{log.Exception}");
}
}
}
-9
View File
@@ -1,9 +0,0 @@
using WpfExtended.Models;
namespace WpfExtended.Logging
{
public interface ILogsWriter
{
void WriteLog(Log log);
}
}
-46
View File
@@ -1,46 +0,0 @@
using Microsoft.Extensions.Logging;
using Slim.Resolvers;
using System.Linq;
namespace System.Windows.Extensions.Logging
{
public sealed class LoggerResolver : IDependencyResolver
{
public bool CanResolve(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>) ||
type == typeof(ILogger))
{
return true;
}
return false;
}
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILogger<>))
{
return ResolveScopedLogger(serviceProvider, type);
}
else
{
return ResolveLogger(serviceProvider, type);
}
}
private static object ResolveScopedLogger(Slim.IServiceProvider serviceProvider, Type type)
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var categoryTypes = type.GetGenericArguments();
var createLoggerMethod = typeof(LoggerFactoryExtensions).GetMethods().Where(m => m.IsGenericMethodDefinition && m.Name == nameof(LoggerFactoryExtensions.CreateLogger)).First();
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
}
private static object ResolveLogger(Slim.IServiceProvider serviceProvider, Type type)
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return loggerFactory.CreateLogger(string.Empty);
}
}
}
-16
View File
@@ -1,16 +0,0 @@
using Microsoft.Extensions.Logging;
using System;
namespace WpfExtended.Models
{
public sealed record Log
{
public Exception Exception { get; set; }
public DateTime LogTime { get; set; }
public string Category { get; set; }
public string EventId { get; set; }
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public string CorrelationVector { get; set; }
}
}
@@ -0,0 +1,8 @@
namespace System.Windows.Extensions.Services
{
public interface IApplicationLifetimeService
{
void OnStartup();
void OnClosing();
}
}
+17 -4
View File
@@ -2,16 +2,29 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ShaderDir>$(ProjectDir)</ShaderDir>
<Fxc>$(SolutionDir)\tools\fxc.exe</Fxc>
<!-- Use MSBuildProjectDirectory to get a more reliable path to the solution root -->
<SolutionRootDir Condition="'$(SolutionDir)' == '' OR '$(SolutionDir)' == '*Undefined*'">$(MSBuildProjectDirectory)\..</SolutionRootDir>
<SolutionRootDir Condition="'$(SolutionDir)' != '' AND '$(SolutionDir)' != '*Undefined*'">$(SolutionDir)</SolutionRootDir>
<Fxc>$(SolutionRootDir)\tools\fxc.exe</Fxc>
<FxcArgs>/O3 /T ps_3_0 /nologo /Fo</FxcArgs>
</PropertyGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Message Importance="High" Text="Compiling shader effect files..." />
<ItemGroup>
<!-- Check if fxc.exe exists before attempting compilation -->
<PropertyGroup>
<FxcExists Condition="Exists('$(Fxc)')">true</FxcExists>
</PropertyGroup>
<Message Importance="High" Text="Looking for fxc.exe at: $(Fxc)" />
<Message Condition="'$(FxcExists)' == 'true'" Importance="High" Text="Compiling shader effect files..." />
<Message Condition="'$(FxcExists)' != 'true'" Importance="High" Text="fxc.exe not found at $(Fxc), using pre-compiled shaders..." />
<ItemGroup Condition="'$(FxcExists)' == 'true'">
<_ShaderFiles Include="$(ShaderDir)**\*.fx" />
</ItemGroup>
<Exec Command="&quot;$(Fxc)&quot; $(FxcArgs) &quot;$([System.IO.Path]::ChangeExtension('%(_ShaderFiles.Identity)', '.ps'))&quot; &quot;%(_ShaderFiles.Identity)&quot;" />
<Exec Condition="'$(FxcExists)' == 'true'" Command="&quot;$(Fxc)&quot; $(FxcArgs) &quot;$([System.IO.Path]::ChangeExtension('%(_ShaderFiles.Identity)', '.ps'))&quot; &quot;%(_ShaderFiles.Identity)&quot;" />
<ItemGroup>
<Resource Include="$(ShaderDir)**\*.ps" />
</ItemGroup>
+19 -15
View File
@@ -1,12 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net5.0-windows;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net10.0-windows</TargetFrameworks>
<UseWPF>true</UseWPF>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>License.txt</PackageLicenseFile>
<Version>0.4.2</Version>
<Version>0.9.0</Version>
<LangVersion>latest</LangVersion>
<Description>Extension library for Windows Presentation Platform.
@@ -24,10 +22,12 @@ http://www.java2s.com/Open-Source/CSharp_Free_Code/Windows_Presentation_Foundati
<None Remove="Effects\ColorKeyAlpha\ColorKeyAlpha.ps" />
<None Remove="Effects\ColorTone\ColorTone.ps" />
<None Remove="Effects\ContrastAdjust\ContrastAdjust.ps" />
<None Remove="Effects\DepthBlur\DepthBlur.ps" />
<None Remove="Effects\DirectionalBlur\DirectionalBlur.ps" />
<None Remove="Effects\Embossed\Embossed.ps" />
<None Remove="Effects\Gloom\Gloom.ps" />
<None Remove="Effects\GrowablePoissonDisk\GrowablePoissonDisk.ps" />
<None Remove="Effects\Impasto\Impasto.ps" />
<None Remove="Effects\InvertColor\InvertColor.ps" />
<None Remove="Effects\Kuwahara\Kuwahara.ps" />
<None Remove="Effects\LightStreak\LightStreak.ps" />
@@ -35,11 +35,13 @@ http://www.java2s.com/Open-Source/CSharp_Free_Code/Windows_Presentation_Foundati
<None Remove="Effects\Monochrome\Monochrome.ps" />
<None Remove="Effects\MotionBlur\MotionBlur.ps" />
<None Remove="Effects\Negative\Negative.ps" />
<None Remove="Effects\Noise\Noise.ps" />
<None Remove="Effects\Pinch\Pinch.ps" />
<None Remove="Effects\Pixelate\Pixelate.ps" />
<None Remove="Effects\Ripple\Ripple.ps" />
<None Remove="Effects\Sharpen\Sharpen.ps" />
<None Remove="Effects\SmoothMagnify\SmoothMagnify.ps" />
<None Remove="Effects\Snowfall\Snowfall.ps" />
<None Remove="Effects\Swirl\Swirl.ps" />
<None Remove="Effects\ToneMapping\ToneMapping.ps" />
<None Remove="Effects\ToonShader\ToonShader.ps" />
@@ -48,7 +50,11 @@ http://www.java2s.com/Open-Source/CSharp_Free_Code/Windows_Presentation_Foundati
<ItemGroup>
<EmbeddedResource Include="Effects\BandedSwirl\BandedSwirl.ps" />
<EmbeddedResource Include="Effects\Snowfall\Snowfall.ps" />
<EmbeddedResource Include="Effects\Bloom\Bloom.ps" />
<EmbeddedResource Include="Effects\DepthBlur\DepthBlur.ps" />
<EmbeddedResource Include="Effects\Impasto\Impasto.ps" />
<EmbeddedResource Include="Effects\Noise\Noise.ps" />
<EmbeddedResource Include="Effects\BrightExtract\BrightExtract.ps" />
<EmbeddedResource Include="Effects\ColorKeyAlpha\ColorKeyAlpha.ps" />
<EmbeddedResource Include="Effects\ColorTone\ColorTone.ps" />
@@ -76,18 +82,16 @@ http://www.java2s.com/Open-Source/CSharp_Free_Code/Windows_Presentation_Foundati
</ItemGroup>
<ItemGroup>
<None Include="License.txt">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.1" />
<PackageReference Include="Slim" Version="1.11.2" />
<PackageReference Include="Slim.Integration" Version="1.0.4" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.6.12" />
<PackageReference Include="SystemExtensions.NetStandard.DependencyInjection" Version="1.6.9" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="5.0.0" />
<PackageReference Include="Slim" Version="1.4.3" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
</ItemGroup>
<Import Project="ShaderCompiler.target" />
</Project>