diff --git a/src/ReactiveUI.WPF.SampleApp/ViewBindingModels/QuestionnaireViewBindingModels.cs b/src/ReactiveUI.WPF.SampleApp/ViewBindingModels/QuestionnaireViewBindingModels.cs index 85c6a362..e2739951 100644 --- a/src/ReactiveUI.WPF.SampleApp/ViewBindingModels/QuestionnaireViewBindingModels.cs +++ b/src/ReactiveUI.WPF.SampleApp/ViewBindingModels/QuestionnaireViewBindingModels.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Windows.Controls; +using System.Windows.Input; using System.Windows.Media; using ReactiveUI.WPF.SampleApp.ViewModels; using ReactiveUI.WPF.SampleApp.Views; @@ -25,7 +26,7 @@ protected override IEnumerable(vw => vw.LaunchInteraction) { - Command = new CommandBinding(vm => vm.LaunchInteraction) + BindCommand = new CommandBinding(vm => vm.LaunchInteraction) }; // Forename diff --git a/src/Vetuviem.Blazor.SourceGenerator/BlazorPlatformResolver.cs b/src/Vetuviem.Blazor.SourceGenerator/BlazorPlatformResolver.cs index 1b08dc55..507110c7 100644 --- a/src/Vetuviem.Blazor.SourceGenerator/BlazorPlatformResolver.cs +++ b/src/Vetuviem.Blazor.SourceGenerator/BlazorPlatformResolver.cs @@ -29,6 +29,12 @@ public string GetBaseUiElement() return "global::Microsoft.AspNetCore.Components.IComponent"; } + /// + public string? GetCommandSourceInterface() + { + return null; + } + /// public string? GetCommandInterface() { diff --git a/src/Vetuviem.Core/CommandBinding.cs b/src/Vetuviem.Core/CommandBinding.cs index 5b30a0e8..c6f11299 100644 --- a/src/Vetuviem.Core/CommandBinding.cs +++ b/src/Vetuviem.Core/CommandBinding.cs @@ -4,7 +4,6 @@ using System; using System.Linq.Expressions; -using System.Reactive; using System.Reactive.Disposables; using System.Windows.Input; using ReactiveUI; @@ -15,10 +14,10 @@ namespace Vetuviem.Core /// Represents a command binding between a control and a viewmodel. /// /// The type for the viewmodel. - public sealed class CommandBinding : ICommandBinding + public sealed class CommandBinding : ICommandBinding where TViewModel : class { - private readonly Expression?>> _viewModelBinding; + private readonly Expression> _viewModelBinding; private readonly string? _toEvent; /// @@ -27,7 +26,7 @@ public sealed class CommandBinding : ICommandBindingExpression for the View Model binding. /// If specified, bind to the specific event instead of the default. public CommandBinding( - Expression?>> viewModelBinding, + Expression> viewModelBinding, string? toEvent = null) { _viewModelBinding = viewModelBinding; @@ -35,11 +34,11 @@ public CommandBinding( } /// - public void ApplyBinding( + public void ApplyBinding( Action disposeAction, TView view, TViewModel viewModel, - Expression> viewBinding) + Expression> viewBinding) where TView : class, IViewFor { if (disposeAction == null) @@ -70,11 +69,11 @@ public void ApplyBinding( } /// - public void ApplyBinding( + public void ApplyBinding( CompositeDisposable compositeDisposable, TView view, TViewModel viewModel, - Expression> viewBinding) + Expression> viewBinding) where TView : class, IViewFor { if (compositeDisposable == null) diff --git a/src/Vetuviem.Core/ICommandBinding.cs b/src/Vetuviem.Core/ICommandBinding.cs index 2a94e09a..18c5b54d 100644 --- a/src/Vetuviem.Core/ICommandBinding.cs +++ b/src/Vetuviem.Core/ICommandBinding.cs @@ -13,19 +13,19 @@ namespace Vetuviem.Core /// Represents a View to View Model Binding for Commands. /// /// The type for the ViewModel. - /// The type for the View. - public interface ICommandBinding + public interface ICommandBinding where TViewModel : class { /// /// Applies a View to View Model Binding. /// /// The type for the view. + /// The type for the View Property. /// The disposable action registration. Used to clean up when bindings fall out of scope. /// The instance of the View to bind. /// The instance of the ViewModel to Bind. /// Expression of the View Property to Bind to. - void ApplyBinding( + void ApplyBinding( Action d, TView view, TViewModel viewModel, @@ -36,11 +36,12 @@ void ApplyBinding( /// Applies a View to View Model Binding. /// /// The type for the view. + /// The type for the View Property. /// The disposable action registration. Used to clean up when bindings fall out of scope. /// The instance of the View to bind. /// The instance of the ViewModel to Bind. /// Expression of the View Property to Bind to. - void ApplyBinding( + void ApplyBinding( CompositeDisposable compositeDisposable, TView view, TViewModel viewModel, diff --git a/src/Vetuviem.SourceGenerator/AbstractBaseSourceGenerator.cs b/src/Vetuviem.SourceGenerator/AbstractBaseSourceGenerator.cs index f3e5bc12..df9eb768 100644 --- a/src/Vetuviem.SourceGenerator/AbstractBaseSourceGenerator.cs +++ b/src/Vetuviem.SourceGenerator/AbstractBaseSourceGenerator.cs @@ -230,7 +230,7 @@ public void Execute(GeneratorExecutionContext context) return namespaceDeclaration; } - var desiredCommandInterface = platformResolver.GetCommandInterface(); + var desiredCommandInterface = platformResolver.GetCommandSourceInterface(); var generatorProcessor = new TGeneratorProcessor(); @@ -247,7 +247,8 @@ public void Execute(GeneratorExecutionContext context) platformName, namespaceName, makeClassesPublic, - includeObsoleteItems); + includeObsoleteItems, + platformResolver.GetCommandInterface()); return result; } diff --git a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/AbstractControlBindingModelClassGenerator.cs b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/AbstractControlBindingModelClassGenerator.cs index b0ba30b4..95b0984b 100644 --- a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/AbstractControlBindingModelClassGenerator.cs +++ b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/AbstractControlBindingModelClassGenerator.cs @@ -25,7 +25,8 @@ public ClassDeclarationSyntax GenerateClass( string platformName, string rootNamespace, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { var typeParameterList = GetTypeParameterListSyntax(namedTypeSymbol); @@ -60,7 +61,8 @@ public ClassDeclarationSyntax GenerateClass( controlClassFullName, platformName, makeClassesPublic, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); return classDeclaration .WithModifiers(modifiers) @@ -191,7 +193,8 @@ protected abstract SyntaxList ApplyMembers( string controlClassFullName, string platformName, bool makeClassesPublic, - bool includeObsoleteItems); + bool includeObsoleteItems, + string? platformCommandType); /// /// Gets the class name identifier from a named type symbol. diff --git a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBindingModelPropertyGenerator.cs b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBindingModelPropertyGenerator.cs index 15bd8247..0db84d28 100644 --- a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBindingModelPropertyGenerator.cs +++ b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBindingModelPropertyGenerator.cs @@ -30,7 +30,8 @@ public static SyntaxList GetProperties( INamedTypeSymbol namedTypeSymbol, string? desiredCommandInterface, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { if (namedTypeSymbol == null) { @@ -42,8 +43,21 @@ public static SyntaxList GetProperties( .Where(x => x.Kind == SymbolKind.Property) .ToArray(); + var fullName = namedTypeSymbol.GetFullName(); + var nodes = new List(properties.Length); + if (!string.IsNullOrWhiteSpace(desiredCommandInterface) + && !string.IsNullOrWhiteSpace(platformCommandType) + && namedTypeSymbol.Interfaces.Any(interfaceName => interfaceName.GetFullName().Equals(desiredCommandInterface, StringComparison.Ordinal))) + { + var bindCommandPropertyDeclaration = GetBindCommandPropertyDeclaration( + makeClassesPublic, + fullName, + platformCommandType!); + nodes.Add(bindCommandPropertyDeclaration); + } + foreach (var prop in properties) { var propertySymbol = prop as IPropertySymbol; @@ -74,15 +88,7 @@ public static SyntaxList GetProperties( continue; } - var accessorList = new[] - { - SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) - .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), - SyntaxFactory.AccessorDeclaration(SyntaxKind.InitAccessorDeclaration) - .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) - }; - - var fullName = namedTypeSymbol.GetFullName(); + var accessorList = GetAccessorDeclarationSyntaxes(); var summary = XmlSyntaxFactory.GenerateSummarySeeAlsoComment( "Gets or sets the binding logic for {0}", @@ -101,6 +107,36 @@ public static SyntaxList GetProperties( return new SyntaxList(nodes); } + private static AccessorDeclarationSyntax[] GetAccessorDeclarationSyntaxes() + { + var accessorList = new[] + { + SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), + SyntaxFactory.AccessorDeclaration(SyntaxKind.InitAccessorDeclaration) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) + }; + return accessorList; + } + + private static MemberDeclarationSyntax GetBindCommandPropertyDeclaration( + bool makeClassesPublic, + string fullName, + string platformCommandType) + { + var accessorList = GetAccessorDeclarationSyntaxes(); + + var summary = XmlSyntaxFactory.GenerateSummarySeeAlsoComment( + "Gets or sets the command binding logic for {0}", + fullName); + + return GetBindCommandPropertyDeclaration( + accessorList, + summary, + makeClassesPublic, + platformCommandType); + } + private static bool ReplacesBaseProperty( IPropertySymbol propertySymbol, INamedTypeSymbol namedTypeSymbol) @@ -128,6 +164,25 @@ private static bool ReplacesBaseProperty( return false; } + private static PropertyDeclarationSyntax GetBindCommandPropertyDeclaration( + AccessorDeclarationSyntax[] accessorList, + IEnumerable summary, + bool makeClassesPublic, + string platformCommandType) + { + TypeSyntax type = GetCommandBindingTypeSyntax(platformCommandType); + + var result = SyntaxFactory.PropertyDeclaration( + type, + "BindCommand") + .AddModifiers(SyntaxFactory.Token(makeClassesPublic ? SyntaxKind.PublicKeyword : SyntaxKind.InternalKeyword)) + .WithAccessorList( + SyntaxFactory.AccessorList(SyntaxFactory.List(accessorList))) + .WithLeadingTrivia(summary); + + return result; + } + private static PropertyDeclarationSyntax GetPropertyDeclaration( IPropertySymbol prop, AccessorDeclarationSyntax[] accessorList, @@ -148,6 +203,12 @@ private static PropertyDeclarationSyntax GetPropertyDeclaration( return result; } + private static TypeSyntax GetCommandBindingTypeSyntax(string platformCommandType) + { + var type = SyntaxFactory.ParseTypeName($"global::Vetuviem.Core.ICommandBinding?"); + return type; + } + private static TypeSyntax GetBindingTypeSyntax( IPropertySymbol prop, string? desiredCommandInterface) @@ -165,17 +226,6 @@ private static string GetBindingInterfaceName( IPropertySymbol prop, string? desiredCommandInterface) { - if (!string.IsNullOrWhiteSpace(desiredCommandInterface)) - { - var propType = prop.Type; - var isCommand = propType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat).Equals(desiredCommandInterface, StringComparison.Ordinal) - || propType.AllInterfaces.Any(interfaceName => interfaceName.GetFullName().Equals(desiredCommandInterface, StringComparison.Ordinal)); - if (isCommand) - { - return "ICommandBinding"; - } - } - var bindingType = prop.IsReadOnly ? "One" : "OneOrTwo"; return $"I{bindingType}WayBind"; diff --git a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBoundControlBindingModelClassGenerator.cs b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBoundControlBindingModelClassGenerator.cs index a3ef543c..0dfeb368 100644 --- a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBoundControlBindingModelClassGenerator.cs +++ b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBoundControlBindingModelClassGenerator.cs @@ -32,7 +32,8 @@ protected override SyntaxList ApplyMembers( string controlClassFullName, string platformName, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { return members; } diff --git a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/GenericControlBindingModelClassGenerator.cs b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/GenericControlBindingModelClassGenerator.cs index 89d21671..02708e84 100644 --- a/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/GenericControlBindingModelClassGenerator.cs +++ b/src/Vetuviem.SourceGenerator/Features/ControlBindingModels/GenericControlBindingModelClassGenerator.cs @@ -34,25 +34,29 @@ protected override SyntaxList ApplyMembers( string controlClassFullName, string platformName, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { members = members.AddRange(ControlBindingModelPropertyGenerator.GetProperties( namedTypeSymbol, desiredCommandInterface, makeClassesPublic, - includeObsoleteItems)); + includeObsoleteItems, + platformCommandType)); members = members.Add(GetApplyBindingsWithDisposableActionMethod( namedTypeSymbol, isDerivedType, desiredCommandInterface, - includeObsoleteItems)); + includeObsoleteItems, + platformCommandType)); members = members.Add(GetApplyBindingsWithCompositeDisposableMethod( namedTypeSymbol, isDerivedType, desiredCommandInterface, - includeObsoleteItems)); + includeObsoleteItems, + platformCommandType)); return members; } @@ -274,7 +278,8 @@ private static MemberDeclarationSyntax GetApplyBindingsWithDisposableActionMetho INamedTypeSymbol namedTypeSymbol, bool isDerivedType, string? desiredCommandInterface, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { const string methodName = "ApplyBindings"; var returnType = SyntaxFactory.ParseTypeName("void"); @@ -283,7 +288,8 @@ private static MemberDeclarationSyntax GetApplyBindingsWithDisposableActionMetho namedTypeSymbol, isDerivedType, desiredCommandInterface, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); var parameters = RoslynGenerationHelpers.GetParams(new[] { @@ -307,7 +313,8 @@ private static MemberDeclarationSyntax GetApplyBindingsWithCompositeDisposableMe INamedTypeSymbol namedTypeSymbol, bool isDerivedType, string? desiredCommandInterface, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { const string methodName = "ApplyBindings"; var returnType = SyntaxFactory.ParseTypeName("void"); @@ -316,7 +323,8 @@ private static MemberDeclarationSyntax GetApplyBindingsWithCompositeDisposableMe namedTypeSymbol, isDerivedType, desiredCommandInterface, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); var parameters = RoslynGenerationHelpers.GetParams(new[] { @@ -336,11 +344,11 @@ private static MemberDeclarationSyntax GetApplyBindingsWithCompositeDisposableMe return declaration; } - private static StatementSyntax[] GetApplyBindingMethodBody( - INamedTypeSymbol namedTypeSymbol, + private static StatementSyntax[] GetApplyBindingMethodBody(INamedTypeSymbol namedTypeSymbol, bool isDerivedType, string? desiredCommandInterface, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { var body = new List(); @@ -366,6 +374,27 @@ private static StatementSyntax[] GetApplyBindingMethodBody( var oneWayBindingStatements = new List(properties.Length); var twoWayBindingStatements = new List(properties.Length); + if (!string.IsNullOrWhiteSpace(desiredCommandInterface) + && !string.IsNullOrWhiteSpace(platformCommandType) + && namedTypeSymbol.Interfaces.Any(interfaceName => interfaceName.GetFullName().Equals(desiredCommandInterface, StringComparison.Ordinal))) + { + var invokeArgs = new[] + { + "registerForDisposalAction", + "view", + "viewModel", + "VetuviemControlBindingExpression", + }; + + var invocationStatement = RoslynGenerationHelpers.GetMethodOnPropertyOfVariableInvocationSyntax( + $"this", + "BindCommand", + "ApplyBinding", + invokeArgs); + + commandBindingStatements.Add(invocationStatement); + } + foreach (var prop in properties) { var propertySymbol = prop as IPropertySymbol; @@ -406,9 +435,7 @@ private static StatementSyntax[] GetApplyBindingMethodBody( AddInvocationStatementToRelevantCollection( propertySymbol, - desiredCommandInterface, invocationStatement, - commandBindingStatements, oneWayBindingStatements, twoWayBindingStatements); } @@ -423,7 +450,8 @@ private static StatementSyntax[] GetApplyBindingMethodBody( private static StatementSyntax[] GetApplyBindingCompositeDisposableMethodBody(INamedTypeSymbol namedTypeSymbol, bool isDerivedType, string? desiredCommandInterface, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { var body = new List(); @@ -443,12 +471,31 @@ private static StatementSyntax[] GetApplyBindingCompositeDisposableMethodBody(IN body.Add(SyntaxFactory.ExpressionStatement(RoslynGenerationHelpers.GetMethodOnVariableInvocationExpression("base", "ApplyBindings", baseInvokeArgs, false))); } - var controlFullName = namedTypeSymbol.GetFullName(); - var commandBindingStatements = new List(properties.Length); var oneWayBindingStatements = new List(properties.Length); var twoWayBindingStatements = new List(properties.Length); + if (!string.IsNullOrWhiteSpace(desiredCommandInterface) + && !string.IsNullOrWhiteSpace(platformCommandType) + && namedTypeSymbol.Interfaces.Any(interfaceName => interfaceName.GetFullName().Equals(desiredCommandInterface, StringComparison.Ordinal))) + { + var invokeArgs = new[] + { + "compositeDisposable", + "view", + "viewModel", + "VetuviemControlBindingExpression", + }; + + var invocationStatement = RoslynGenerationHelpers.GetMethodOnPropertyOfVariableInvocationSyntax( + $"this", + "BindCommand", + "ApplyBinding", + invokeArgs); + + commandBindingStatements.Add(invocationStatement); + } + foreach (var prop in properties) { var propertySymbol = prop as IPropertySymbol; @@ -471,27 +518,11 @@ private static StatementSyntax[] GetApplyBindingCompositeDisposableMethodBody(IN continue; } - var propType = propertySymbol.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - - var invokeArgs = new[] - { - "compositeDisposable", - "view", - "viewModel", - $"global::Vetuviem.Core.ExpressionHelpers.GetControlPropertyExpressionFromViewExpression(VetuviemControlBindingExpression, \"{propertySymbol.Name}\")", - }; - - var invocationStatement = RoslynGenerationHelpers.GetMethodOnPropertyOfVariableInvocationSyntax( - $"this", - propertySymbol.Name, - "ApplyBinding", - invokeArgs); + var invocationStatement = GetInvocationStatement(propertySymbol); AddInvocationStatementToRelevantCollection( propertySymbol, - desiredCommandInterface, invocationStatement, - commandBindingStatements, oneWayBindingStatements, twoWayBindingStatements); } @@ -503,14 +534,33 @@ private static StatementSyntax[] GetApplyBindingCompositeDisposableMethodBody(IN return body.ToArray(); } + private static StatementSyntax GetInvocationStatement(IPropertySymbol propertySymbol) + { + var propType = propertySymbol.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + + var invokeArgs = new[] + { + "compositeDisposable", + "view", + "viewModel", + $"global::Vetuviem.Core.ExpressionHelpers.GetControlPropertyExpressionFromViewExpression(VetuviemControlBindingExpression, \"{propertySymbol.Name}\")", + }; + + var invocationStatement = RoslynGenerationHelpers.GetMethodOnPropertyOfVariableInvocationSyntax( + $"this", + propertySymbol.Name, + "ApplyBinding", + invokeArgs); + return invocationStatement; + } + private static void AddInvocationStatementToRelevantCollection( IPropertySymbol prop, - string? desiredCommandInterface, StatementSyntax invocation, - ICollection commandBindingStatements, ICollection oneWayBindingStatements, ICollection twoWayBindingStatements) { + /* if (!string.IsNullOrWhiteSpace(desiredCommandInterface)) { var propType = prop.Type; @@ -522,6 +572,7 @@ private static void AddInvocationStatementToRelevantCollection( return; } } + */ if (prop.IsReadOnly) { diff --git a/src/Vetuviem.SourceGenerator/Features/Core/AbstractGeneratorProcessor.cs b/src/Vetuviem.SourceGenerator/Features/Core/AbstractGeneratorProcessor.cs index b26e89dc..73f5b14c 100644 --- a/src/Vetuviem.SourceGenerator/Features/Core/AbstractGeneratorProcessor.cs +++ b/src/Vetuviem.SourceGenerator/Features/Core/AbstractGeneratorProcessor.cs @@ -41,7 +41,8 @@ public NamespaceDeclarationSyntax GenerateNamespaceDeclaration(NamespaceDeclarat string platformName, string rootNamespace, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { if (namespaceDeclaration == null) { @@ -89,7 +90,8 @@ public NamespaceDeclarationSyntax GenerateNamespaceDeclaration(NamespaceDeclarat platformName, rootNamespace, makeClassesPublic, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); } return namespaceDeclaration; @@ -125,7 +127,8 @@ private static void CheckTypeForUiType(INamedTypeSymbol namedTypeSymbol, List memberDeclarationSyntaxes, string rootNamespace, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { var fullName = namedTypeSymbol.GetFullName(); @@ -179,7 +182,8 @@ private static void CheckTypeForUiType(INamedTypeSymbol namedTypeSymbol, platformName, rootNamespace, makeClassesPublic, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); memberDeclarationSyntaxes.Add(generatedClass); } @@ -234,7 +238,8 @@ private NamespaceDeclarationSyntax CheckAssemblyForUiTypes(NamespaceDeclarationS string platformName, string rootNamespace, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { reportDiagnosticAction(ReportDiagnosticFactory.StartingScanOfAssembly(metadataReference)); @@ -269,7 +274,8 @@ private NamespaceDeclarationSyntax CheckAssemblyForUiTypes(NamespaceDeclarationS classGenerators, rootNamespace, makeClassesPublic, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); if (nestedDeclarationSyntax != null) { @@ -302,7 +308,8 @@ private NamespaceDeclarationSyntax CheckAssemblyForUiTypes(NamespaceDeclarationS Func[] classGenerators, string rootNamespace, bool makeClassesPublic, - bool includeObsoleteItems) + bool includeObsoleteItems, + string? platformCommandType) { reportDiagnosticAction(ReportDiagnosticFactory.StartingScanOfNamespace(namespaceSymbol)); @@ -324,7 +331,8 @@ private NamespaceDeclarationSyntax CheckAssemblyForUiTypes(NamespaceDeclarationS nestedMembers, rootNamespace, makeClassesPublic, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); } var nestedSymbols = namespaceSymbol.GetNamespaceMembers(); @@ -342,7 +350,8 @@ private NamespaceDeclarationSyntax CheckAssemblyForUiTypes(NamespaceDeclarationS classGenerators, rootNamespace, makeClassesPublic, - includeObsoleteItems); + includeObsoleteItems, + platformCommandType); if (nestedNamespace != null) { diff --git a/src/Vetuviem.SourceGenerator/Features/Core/IClassGenerator.cs b/src/Vetuviem.SourceGenerator/Features/Core/IClassGenerator.cs index c8137e4b..f7e048fb 100644 --- a/src/Vetuviem.SourceGenerator/Features/Core/IClassGenerator.cs +++ b/src/Vetuviem.SourceGenerator/Features/Core/IClassGenerator.cs @@ -30,6 +30,7 @@ ClassDeclarationSyntax GenerateClass( string platformName, string rootNamespace, bool makeClassesPublic, - bool includeObsoleteItems); + bool includeObsoleteItems, + string? platformCommandType); } } diff --git a/src/Vetuviem.SourceGenerator/Features/Core/IPlatformResolver.cs b/src/Vetuviem.SourceGenerator/Features/Core/IPlatformResolver.cs index 25114cc0..0b22a055 100644 --- a/src/Vetuviem.SourceGenerator/Features/Core/IPlatformResolver.cs +++ b/src/Vetuviem.SourceGenerator/Features/Core/IPlatformResolver.cs @@ -21,6 +21,12 @@ public interface IPlatformResolver /// Fully qualified type name. string GetBaseUiElement(); + /// + /// Gets the fully qualified type that platform uses for binding controls to commands. + /// + /// Fully qualified type name, or null if no command implementation in the platform. + string? GetCommandSourceInterface(); + /// /// Gets the fully qualified type that platform uses for commands. /// diff --git a/src/Vetuviem.WPF.SourceGenerator/WpfPlatformResolver.cs b/src/Vetuviem.WPF.SourceGenerator/WpfPlatformResolver.cs index 04ebc385..f9fffa28 100644 --- a/src/Vetuviem.WPF.SourceGenerator/WpfPlatformResolver.cs +++ b/src/Vetuviem.WPF.SourceGenerator/WpfPlatformResolver.cs @@ -35,6 +35,12 @@ public string GetBaseUiElement() return "global::System.Windows.UIElement"; } + /// + public string GetCommandSourceInterface() + { + return "global::System.Windows.Input.ICommandSource"; + } + /// public string GetCommandInterface() { diff --git a/src/Vetuviem.WinUi.SourceGenerator/WinUi3PlatformResolver.cs b/src/Vetuviem.WinUi.SourceGenerator/WinUi3PlatformResolver.cs index a51dd4b0..fa7a9c38 100644 --- a/src/Vetuviem.WinUi.SourceGenerator/WinUi3PlatformResolver.cs +++ b/src/Vetuviem.WinUi.SourceGenerator/WinUi3PlatformResolver.cs @@ -26,6 +26,12 @@ public string GetBaseUiElement() return "global::Microsoft.UI.Xaml.UIElement"; } + /// + public string? GetCommandSourceInterface() + { + return "global::System.Windows.Input.ICommandSource"; + } + /// public string GetCommandInterface() { diff --git a/src/Vetuviem.Winforms.SourceGenerator/WinformsPlatformResolver.cs b/src/Vetuviem.Winforms.SourceGenerator/WinformsPlatformResolver.cs index e1be475a..f010bf97 100644 --- a/src/Vetuviem.Winforms.SourceGenerator/WinformsPlatformResolver.cs +++ b/src/Vetuviem.Winforms.SourceGenerator/WinformsPlatformResolver.cs @@ -26,6 +26,12 @@ public string GetBaseUiElement() return "global::System.Windows.Forms.Control"; } + /// + public string? GetCommandSourceInterface() + { + return null; + } + /// public string? GetCommandInterface() {