Browse Source

Added MainVmEnum

CPKreuz 2 years ago
parent
commit
93ff4a0196

+ 3 - 3
src/PixiEditor/Helpers/EnumExtension.cs

@@ -12,10 +12,10 @@ public class EnumExtension : MarkupExtension
         EnumType = enumType ?? throw new ArgumentNullException(nameof(enumType));
     }
 
-    public Type EnumType
+    private Type EnumType
     {
-        get { return _enumType; }
-        private set
+        get => _enumType;
+        init
         {
             if (_enumType == value)
                 return;

+ 26 - 1
src/PixiEditor/ViewModels/MainVM.cs

@@ -1,10 +1,35 @@
 using System.Windows.Markup;
+using PixiEditor.ViewModels.SubViewModels;
 
 namespace PixiEditor.ViewModels;
 internal class MainVM : MarkupExtension
 {
+    private MainVmEnum? vm;
+    private static Dictionary<MainVmEnum, object> subVms = new();
+
     public override object ProvideValue(IServiceProvider serviceProvider)
     {
-        return ViewModelMain.Current;
+        return vm != null ? subVms[vm.Value] : ViewModelMain.Current;
+    }
+
+    static MainVM()
+    {
+        var type = typeof(ViewModelMain);
+        var vm = ViewModelMain.Current;
+        
+        foreach (var value in Enum.GetValues<MainVmEnum>())
+        {
+            subVms.Add(value, type.GetProperty(value.ToString())?.GetValue(vm));
+        }
+    }
+    
+    public MainVM()
+    {
+        vm = null;
+    }
+
+    public MainVM(MainVmEnum vm)
+    {
+        this.vm = vm;
     }
 }

+ 25 - 0
src/PixiEditorGen/Extensions.cs

@@ -0,0 +1,25 @@
+using System.Text;
+using Microsoft.CodeAnalysis;
+
+namespace PixiEditorGen;
+
+internal static class Extensions
+{
+    public static bool AssignableTo(this INamedTypeSymbol? type, INamedTypeSymbol target)
+    {
+        while (true)
+        {
+            if (type == null)
+            {
+                return false;
+            }
+
+            if (type.Name == target.Name)
+            {
+                return true;
+            }
+
+            type = type.BaseType;
+        }
+    }
+}

+ 60 - 0
src/PixiEditorGen/MainVMEnumGenerator.cs

@@ -0,0 +1,60 @@
+using System.Diagnostics;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace PixiEditorGen;
+
+[Generator(LanguageNames.CSharp)]
+public class MainVmEnumGenerator : IIncrementalGenerator
+{
+    const string MainVmName = "PixiEditor.ViewModels.ViewModelMain";
+    private const string SubVmName = "PixiEditor.ViewModels.SubViewModels.SubViewModel`1";
+    
+    public void Initialize(IncrementalGeneratorInitializationContext context)
+    {
+        var properties = GetProperties(context);
+        
+        context.RegisterSourceOutput(properties.Collect(), (context, list) =>
+        {
+            AddEnum(context, list.SelectMany(x => x).ToList());
+        });
+    }
+
+    private void AddEnum(SourceProductionContext context, List<PropertyDeclarationSyntax> properties)
+    {
+        var enumDeclaration = SyntaxFactory.EnumDeclaration("MainVmEnum")
+            .AddMembers(properties.Select(property => property.Identifier.ValueText).Select(SyntaxFactory.EnumMemberDeclaration).ToArray());
+        
+        var namespaceDeclaration = SyntaxFactory
+            .NamespaceDeclaration(SyntaxFactory.ParseName("PixiEditor.ViewModels"))
+            .AddMembers(enumDeclaration);
+        
+        context.AddSource("MainVmEnum", namespaceDeclaration.NormalizeWhitespace().ToFullString());
+    }
+
+    private IncrementalValuesProvider<List<PropertyDeclarationSyntax>> GetProperties(IncrementalGeneratorInitializationContext context) => context.SyntaxProvider.CreateSyntaxProvider(
+        (x, _) =>
+        {
+            return x is TypeDeclarationSyntax type && type.Identifier.ValueText.Contains("ViewModelMain");
+        }, 
+        (context, _) =>
+        {
+            var type = context.Node as TypeDeclarationSyntax;
+            var semantic = context.SemanticModel;
+            
+            var properties = type.Members
+                .Where(member => member is PropertyDeclarationSyntax)
+                .Cast<PropertyDeclarationSyntax>();
+
+            var subViewModelType = semantic.Compilation.GetTypeByMetadataName(SubVmName);
+
+            var matching = from property in properties
+                let symbol = ModelExtensions.GetSymbolInfo(semantic, property.Type).Symbol
+                where ((ITypeSymbol)symbol!).BaseType.AssignableTo(subViewModelType!)
+                select property;
+            
+            return matching.ToList();
+        });
+}