From 9406085a99733c98752cbc059d5cabaebb6f2ee1 Mon Sep 17 00:00:00 2001 From: egokb Date: Fri, 20 Dec 2024 18:36:28 +0800 Subject: [PATCH] fix descriptor binding error --- .../BindingContextGenerator.Template.cs | 11 +- .../BindingContextGenerator.cs | 33 +-- .../ContextInfoByAttributeGenerator.cs | 5 +- .../ContextInfoByDescriptorGenerator.cs | 4 - .../ContextInfoGenerators.cs | 5 +- src/FUIStubs.cs | 5 + src/PipeServer/MessageClient.cs | 179 ++++++++++++++++ src/PipeServer/Server.cs | 32 --- src/Program.cs | 4 +- .../ObservableObjectDelegateGenerator.cs | 47 +++-- src/TypeSymbolExtensions.cs | 67 ++++-- src/Utility.cs | 195 +----------------- 12 files changed, 286 insertions(+), 301 deletions(-) create mode 100644 src/PipeServer/MessageClient.cs delete mode 100644 src/PipeServer/Server.cs diff --git a/src/ContextGenerator/BindingContextGenerator.Template.cs b/src/ContextGenerator/BindingContextGenerator.Template.cs index 985417f..bc1079e 100644 --- a/src/ContextGenerator/BindingContextGenerator.Template.cs +++ b/src/ContextGenerator/BindingContextGenerator.Template.cs @@ -6,24 +6,21 @@ public partial class BindingContextGenerator { #region 类模板 - const string DefaultNamespace = "__DataBindingGenerated"; - /// /// 构建绑定上下文 /// - public static string BuildContextCode(ContextBindingInfo contextInfo, string usings, string @namespace, string converters, string bindings, string unbindings, string functions) + public static string BuildContextCode(ContextBindingInfo contextInfo, string converters, string bindings, string unbindings, string functions) { return $$""" {{Utility.FileHead}} -{{usings}} -namespace {{@namespace}} +namespace {{Utility.BindingContextDefaultNamespace}} { [FUI.ViewModelAttribute(typeof({{contextInfo.viewModelType}}))] [FUI.ViewAttribute("{{contextInfo.viewName}}")] - public class __{{contextInfo.viewModelType.ToCSharpName()}}_{{contextInfo.viewName}}_Binding_Generated : FUI.BindingContext + public class {{contextInfo.viewModelType.ToCSharpName()}}_{{contextInfo.viewName}}_Binding_Generated : FUI.BindingContext { {{converters}} - public __{{contextInfo.viewModelType.ToCSharpName()}}_{{contextInfo.viewName}}_Binding_Generated(FUI.IView view, FUI.Bindable.ObservableObject viewModel) : base(view, viewModel) { } + public {{contextInfo.viewModelType.ToCSharpName()}}_{{contextInfo.viewName}}_Binding_Generated(FUI.IView view, FUI.Bindable.ObservableObject viewModel) : base(view, viewModel) { } protected override void Binding() { diff --git a/src/ContextGenerator/BindingContextGenerator.cs b/src/ContextGenerator/BindingContextGenerator.cs index 913a03e..f261705 100644 --- a/src/ContextGenerator/BindingContextGenerator.cs +++ b/src/ContextGenerator/BindingContextGenerator.cs @@ -12,9 +12,6 @@ internal IReadOnlyList Generate(IReadOnlyList contex var result = new List(); foreach (var bindingContext in contexts) { - var usings = new List(0); - var @namespace = string.Empty; - var bindingBuilder = new StringBuilder(); var unbindingBuilder = new StringBuilder(); HashSet converterTypes = new HashSet(); @@ -65,15 +62,8 @@ internal IReadOnlyList Generate(IReadOnlyList contex var convertersBuilder = new StringBuilder(); BuildConverterCostructor(converterTypes, ref convertersBuilder); - //添加using - var usingBuilder = new StringBuilder(); - BuildUsings(usings, ref usingBuilder); - - //添加Namespace - var @namespaceName = string.IsNullOrEmpty(@namespace) ? DefaultNamespace : @namespace; - //组装所有的绑定代码 - var code = BuildContextCode(bindingContext, usingBuilder.ToString(), @namespaceName, convertersBuilder.ToString(), bindingBuilder.ToString(), unbindingBuilder.ToString(), functionBuilder.ToString()); + var code = BuildContextCode(bindingContext, convertersBuilder.ToString(), bindingBuilder.ToString(), unbindingBuilder.ToString(), functionBuilder.ToString()); //格式化代码 code = Utility.NormalizeCode(code); @@ -148,27 +138,6 @@ void BuildConverterCostructor(HashSet converterTypes, ref StringBuilder } } - //构造所有的using - void BuildUsings(IEnumerable usings, ref StringBuilder usingBuilder) - { - if (usings == null) - { - usingBuilder.AppendLine(""); - } - else - { - foreach (var @using in usings) - { - if (string.IsNullOrEmpty(@using)) - { - continue; - } - - usingBuilder.AppendLine($"using {@using};"); - } - } - } - /// /// 生成从View到ViewModel的绑定代码和解绑代码 /// diff --git a/src/ContextInfoGenerator/ContextInfoByAttributeGenerator.cs b/src/ContextInfoGenerator/ContextInfoByAttributeGenerator.cs index 732256f..2fa6a09 100644 --- a/src/ContextInfoGenerator/ContextInfoByAttributeGenerator.cs +++ b/src/ContextInfoGenerator/ContextInfoByAttributeGenerator.cs @@ -158,14 +158,13 @@ PropertyBindingInfo CreatePropertyBindingInfo(SemanticModel semanticModel, Class PropertyInfo CreatePropertyInfo(SemanticModel semanticModel, ClassDeclarationSyntax clazz, PropertyDeclarationSyntax property, AttributeSyntax attribute) { var propertyName = property.Identifier.Text; - var propertyType = semanticModel.GetTypeInfo(property).Type; - var isList = Utility.IsObservableList(clazz, property); + var propertyType = semanticModel.GetTypeInfo(property.Type).Type; return new PropertyInfo { name = propertyName, type = propertyType.ToString(), - isList = isList, + isList = propertyType.IsObservableList(), location = property.GetLocation().ToLocationInfo(), }; } diff --git a/src/ContextInfoGenerator/ContextInfoByDescriptorGenerator.cs b/src/ContextInfoGenerator/ContextInfoByDescriptorGenerator.cs index 520c215..aea5907 100644 --- a/src/ContextInfoGenerator/ContextInfoByDescriptorGenerator.cs +++ b/src/ContextInfoGenerator/ContextInfoByDescriptorGenerator.cs @@ -17,10 +17,6 @@ public List Generate(SemanticModel semanticModel, SyntaxNode foreach (var classDeclaration in classDeclarations) { var classType = semanticModel.GetDeclaredSymbol(classDeclaration); - if(classType.ToString() == "Test.Descriptor.TestDescriptorContextDescriptor") - { - var a = 0; - } if(!classType.IsContextDescriptor(out var viewModelType)) { continue; diff --git a/src/ContextInfoGenerator/ContextInfoGenerators.cs b/src/ContextInfoGenerator/ContextInfoGenerators.cs index fa75c17..713bd31 100644 --- a/src/ContextInfoGenerator/ContextInfoGenerators.cs +++ b/src/ContextInfoGenerator/ContextInfoGenerators.cs @@ -76,7 +76,7 @@ internal async Task> Generate(Project project, /// 输出文件夹 void TrySaveToFile(ContextBindingInfo info, string output) { - if (!string.IsNullOrEmpty(output)) + if (string.IsNullOrEmpty(output)) { return; } @@ -87,7 +87,8 @@ void TrySaveToFile(ContextBindingInfo info, string output) } var json = Newtonsoft.Json.JsonConvert.SerializeObject(info, Newtonsoft.Json.Formatting.Indented); - var fileName = $"{Utility.GetBindingContextTypeName(info)}.binding"; + //这个文件名要保持和上下文类型的全名一致 以便于后续根据上下文类型查找对应的绑定信息 + var fileName = $"{Utility.GetBindingContextTypeFullName(info)}.binding"; var file = Path.Combine(output, fileName); File.WriteAllText(file, json); } diff --git a/src/FUIStubs.cs b/src/FUIStubs.cs index 9c76d52..6dd7260 100644 --- a/src/FUIStubs.cs +++ b/src/FUIStubs.cs @@ -7,6 +7,11 @@ public class CommandAttribute : Attribute { } public interface IValueConverter { } public interface IValueConverter { } + + public interface ISynchronizeProperties + { + void Synchronize(); + } } namespace FUI.BindingDescriptor diff --git a/src/PipeServer/MessageClient.cs b/src/PipeServer/MessageClient.cs new file mode 100644 index 0000000..8c3cce5 --- /dev/null +++ b/src/PipeServer/MessageClient.cs @@ -0,0 +1,179 @@ +using System.IO.Pipes; + +namespace FUICompiler +{ + internal class MessageClient : IDisposable + { + const string PipeName = "FUICompilerMessage"; + const int BufferSize = 1024; + readonly NamedPipeClientStream pipeClient; + readonly Queue sendQueue = new Queue(); + readonly CancellationTokenSource cts = new CancellationTokenSource(); + + public event Action MessageReceived; + public event Action Connected; + public event Action Disconnected; + + static MessageClient instance; + + public static MessageClient Instance + { + get + { + if (instance == null) + { + instance = new MessageClient(); + } + + return instance; + } + } + + MessageClient() + { + pipeClient = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous); + } + + public async Task ConnectAsync(int timeoutMs = 5000) + { + if (IsConnected) + { + return; + } + + try + { + await pipeClient.ConnectAsync(timeoutMs, cts.Token); + Connected?.Invoke(); + + // 启动读写任务 + _ = ReadMessagesAsync(); + _ = ProcessSendQueueAsync(); + } + catch (Exception) + { + throw; + } + } + + public void Send(byte[] bytes) + { + if (!IsConnected) + { + throw new InvalidOperationException("未连接到服务器"); + } + + lock (sendQueue) + { + sendQueue.Enqueue(bytes); + } + } + + async Task ReadMessagesAsync() + { + var buffer = new byte[BufferSize]; + + try + { + while (IsConnected && !cts.Token.IsCancellationRequested) + { + var message = new List(); + do + { + var bytesRead = await pipeClient.ReadAsync(buffer, 0, buffer.Length, cts.Token); + if (bytesRead == 0) + { + break; + } + + for (int i = 0; i < bytesRead; i++) + { + message.Add(buffer[i]); + } + } + while (!pipeClient.IsMessageComplete); + + MessageReceived?.Invoke(message.ToArray()); + } + } + catch (IOException) + { + // 服务端断开连接 + HandleDisconnection(); + } + catch (OperationCanceledException) + { + // 正常取消 + } + } + + async Task ProcessSendQueueAsync() + { + try + { + while (IsConnected && !cts.Token.IsCancellationRequested) + { + byte[] message = null; + + lock (sendQueue) + { + if (sendQueue.Count > 0) + { + message = sendQueue.Dequeue(); + } + } + + if (message != null) + { + await pipeClient.WriteAsync(message, 0, message.Length, cts.Token); + await pipeClient.FlushAsync(cts.Token); + } + else + { + await Task.Delay(100, cts.Token); // 避免空轮询 + } + } + } + catch (IOException) + { + // 服务端断开连接 + HandleDisconnection(); + } + catch (OperationCanceledException) + { + // 正常取消 + } + } + + void HandleDisconnection() + { + if (!IsConnected) + { + return; + } + + Disconnected?.Invoke(); + } + + public void Disconnect() + { + if (!IsConnected) + { + return; + } + + cts.Cancel(); + pipeClient.Close(); + Disconnected?.Invoke(); + } + + public void Dispose() + { + Disconnect(); + cts.Dispose(); + pipeClient.Dispose(); + } + + public bool IsConnected => pipeClient.IsConnected; + } +} \ No newline at end of file diff --git a/src/PipeServer/Server.cs b/src/PipeServer/Server.cs deleted file mode 100644 index 9c5a0b0..0000000 --- a/src/PipeServer/Server.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.IO.Pipes; -using System.Security.Principal; - -namespace FUICompiler -{ - internal class Server - { - void Start() - { - // 服务端 - using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 1)) - { - Console.WriteLine("Named pipe server is running..."); - pipeServer.WaitForConnection(); - using (StreamWriter sw = new StreamWriter(pipeServer)) - { - sw.WriteLine("Hello, client!"); - } - } - - // 客户端 - using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.None)) - { - pipeClient.Connect(); - using (StreamReader sr = new StreamReader(pipeClient)) - { - Console.WriteLine(sr.ReadToEnd()); - } - } - } - } -} diff --git a/src/Program.cs b/src/Program.cs index 0d4a88f..19891da 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -11,8 +11,8 @@ try { - string workspace = "..\\..\\..\\..\\..\\..\\FUI\\"; - args = $"--sln={workspace}.\\FUI.sln --project=FUI.Test --output={workspace}.\\Library\\ScriptAssemblies --binding={workspace}.\\Binding\\ --generated={workspace}.\\FUI\\Generated\\ --ctx_type=Mix --binding_output={workspace}.\\FUI\\BindingInfo\\".Split(' '); + //string workspace = "..\\..\\..\\..\\..\\..\\FUI\\"; + //args = $"--sln={workspace}.\\FUI.sln --project=FUI.Test --output={workspace}.\\Library\\ScriptAssemblies --binding={workspace}.\\Binding\\ --generated={workspace}.\\FUI\\Generated\\ --ctx_type=Mix --binding_output={workspace}.\\FUI\\BindingInfo\\".Split(' '); var param = ParseArgs(args); var compiler = new Compiler(param); await compiler.Build(); diff --git a/src/PropertyDelegateGenerator/ObservableObjectDelegateGenerator.cs b/src/PropertyDelegateGenerator/ObservableObjectDelegateGenerator.cs index c42605d..bd08cba 100644 --- a/src/PropertyDelegateGenerator/ObservableObjectDelegateGenerator.cs +++ b/src/PropertyDelegateGenerator/ObservableObjectDelegateGenerator.cs @@ -22,16 +22,16 @@ internal List Generate(SemanticModel semanticModel, SyntaxNode root) var sources = new List(); foreach(var classDeclaration in classDeclarations) { - var type = semanticModel.GetDeclaredSymbol(classDeclaration); + var classType = semanticModel.GetDeclaredSymbol(classDeclaration); //如果不是可观察对象直接不管 - if (!type.IsObservableObject()) + if (!classType.IsObservableObject()) { continue; } //如果是静态类或者抽象类直接不管 - if (type.IsAbstract || type.IsStatic) + if (classType.IsAbstract || classType.IsStatic) { continue; } @@ -51,7 +51,7 @@ internal List Generate(SemanticModel semanticModel, SyntaxNode root) } //判断是否有命名空间 - var @namespace = type.ContainingNamespace.ToDisplayString(); + var @namespace = classType.ContainingNamespace.ToDisplayString(); var hasNamespace = !string.IsNullOrEmpty(@namespace); if (hasNamespace) { @@ -60,7 +60,7 @@ internal List Generate(SemanticModel semanticModel, SyntaxNode root) } //生成分布类 - appendBuilder.AppendLine($"public partial class {type.Name} : {Utility.SynchronizePropertiesFullName}"); + appendBuilder.AppendLine($"public partial class {classType.Name} : {typeof(FUI.ISynchronizeProperties).FullName}"); appendBuilder.AppendLine("{"); var syncPropertiesBuilder = new StringBuilder(); @@ -68,13 +68,10 @@ internal List Generate(SemanticModel semanticModel, SyntaxNode root) //遍历所有属性 生成对应委托 foreach (var property in classDeclaration.ChildNodes().OfType()) { - //if (!Utility.IsObservableProperty(classDeclaration, property)) - //{ - // continue; - //} + var propertyTypeInfo = semanticModel.GetDeclaredSymbol(property); - var propertyType = property.Type.ToString(); - var propertyName = property.Identifier.Text; + var propertyType = propertyTypeInfo.Type.ToString(); + var propertyName = propertyTypeInfo.Name; //生成BackingField var fieldName = Utility.GetPropertyBackingFieldName(propertyName); @@ -94,7 +91,7 @@ internal List Generate(SemanticModel semanticModel, SyntaxNode root) var events = classDeclaration.DescendantNodes().OfType().ToArray(); foreach (var @event in events) { - var eventCaller = GenerateEventCaller(@event); + var eventCaller = GenerateEventCaller(semanticModel, @event); appendBuilder.AppendLine(eventCaller); } @@ -107,7 +104,7 @@ internal List Generate(SemanticModel semanticModel, SyntaxNode root) appendBuilder.AppendLine("}"); } var code = Utility.NormalizeCode(appendBuilder.ToString()); - sources.Add(new Source($"{classDeclaration.Identifier.Text}.PropertyChanged.g", code)); + sources.Add(new Source($"{classType.ToString()}.PropertyChanged.g", code)); } return sources; @@ -121,7 +118,7 @@ internal List Generate(SemanticModel semanticModel, SyntaxNode root) void GenerateSyncPropertites(StringBuilder propertyDelegateBuilder, StringBuilder syncPropertiesBuilder) { //生成同步所有属性的方法 - propertyDelegateBuilder.AppendLine($"void {Utility.SynchronizePropertiesFullName}.{Utility.SynchronizePropertiesMethodName}()"); + propertyDelegateBuilder.AppendLine($"void {typeof(FUI.ISynchronizeProperties).FullName}.{nameof(FUI.ISynchronizeProperties.Synchronize)}()"); propertyDelegateBuilder.AppendLine("{"); propertyDelegateBuilder.AppendLine(syncPropertiesBuilder.ToString()); propertyDelegateBuilder.AppendLine("}"); @@ -132,14 +129,28 @@ void GenerateSyncPropertites(StringBuilder propertyDelegateBuilder, StringBuilde /// /// 事件字段 /// - string GenerateEventCaller(EventFieldDeclarationSyntax syntax) + string GenerateEventCaller(SemanticModel semanticModel, EventFieldDeclarationSyntax syntax) { - var argsType = (syntax.Declaration.Type as GenericNameSyntax).TypeArgumentList.Arguments; + var eventTypeInfo = semanticModel.GetTypeInfo(syntax.Declaration.Type); + var namedEventType = eventTypeInfo.Type as INamedTypeSymbol; + var argsTypesString = string.Empty; + var invokeParams = string.Empty; + if (namedEventType.IsGenericType) + { + var argsTypes = namedEventType.TypeArguments; + for(int i = 0; i< argsTypes.Length; i++) + { + var end = i == argsTypes.Length - 1 ? string.Empty : ","; + argsTypesString += $"{argsTypes[i]} arg{i}{end}"; + invokeParams += $"arg{i}{end}"; + } + } + var callerName = Utility.GetEventMethodName(syntax.Declaration.Variables.ToString()); return $$""" -public void {{callerName}} ({{argsType}} args) +public void {{callerName}} ({{argsTypesString}}) { - this.{{syntax.Declaration.Variables}}?.Invoke(args); + this.{{syntax.Declaration.Variables}}?.Invoke({{invokeParams}}); } """; } diff --git a/src/TypeSymbolExtensions.cs b/src/TypeSymbolExtensions.cs index 0c26e22..edb8846 100644 --- a/src/TypeSymbolExtensions.cs +++ b/src/TypeSymbolExtensions.cs @@ -6,23 +6,55 @@ namespace FUICompiler { internal static class TypeSymbolExtensions { - public static bool Extends(this ITypeSymbol symbol, Type type) + static Queue cache = new Queue(); + + /// + /// 判断一个类型是否继承自某个类型或者实现了某个接口 + /// + /// 源类型 + /// 目标类型 + /// + internal static bool Extends(this ITypeSymbol symbol, Type type) { if (symbol == null || type == null) + { return false; + } + + var openList = cache; + openList.Clear(); + openList.Enqueue(symbol); - while (symbol != null) + while(openList.Count > 0) { - if (symbol.Matches(type)) + var current = openList.Dequeue(); + + if (current.Matches(type)) + { return true; + } + + if (current.BaseType != null) + { + openList.Enqueue(current.BaseType); + } - symbol = symbol.BaseType; + foreach (var @interface in current.Interfaces) + { + openList.Enqueue(@interface); + } } return false; } - public static bool Matches(this ITypeSymbol symbol, Type type) + /// + /// 判断一个类型是否和另一个类型匹配 + /// + /// 源类型 + /// 目标类型 + /// + internal static bool Matches(this ITypeSymbol symbol, Type type) { switch (symbol.SpecialType) { @@ -42,23 +74,30 @@ public static bool Matches(this ITypeSymbol symbol, Type type) } if (!(symbol is INamedTypeSymbol named)) + { return false; + } if (type.IsConstructedGenericType) { var args = type.GetTypeInfo().GenericTypeArguments; if (args.Length != named.TypeArguments.Length) + { return false; + } for (var i = 0; i < args.Length; i++) + { if (!Matches(named.TypeArguments[i], args[i])) + { return false; - + } + } + return Matches(named.ConstructedFrom, type.GetGenericTypeDefinition()); } - return named.MetadataName == type.Name - && named.ContainingNamespace?.ToDisplayString() == type.Namespace; + return named.MetadataName == type.Name && named.ContainingNamespace?.ToDisplayString() == type.Namespace; } /// @@ -70,15 +109,9 @@ public static bool Matches(this ITypeSymbol symbol, Type type) internal static bool IsType(this ITypeSymbol symbol, Type type) { return Matches(symbol, type); - if (!(symbol is INamedTypeSymbol named)) - { - return false; - } - - return named.Name == type.Name && named.ContainingNamespace?.ToDisplayString() == type.Namespace; } - public static IEnumerable GetBaseTypesAndThis(this ITypeSymbol type) + internal static IEnumerable GetBaseTypesAndThis(this ITypeSymbol type) { var current = type; while (current != null) @@ -88,7 +121,7 @@ public static IEnumerable GetBaseTypesAndThis(this ITypeSymbol type } } - public static bool InheritsFromOrEquals(this ITypeSymbol type, ITypeSymbol baseType) + internal static bool InheritsFromOrEquals(this ITypeSymbol type, ITypeSymbol baseType) { foreach (var t in type.GetBaseTypesAndThis()) { @@ -101,7 +134,7 @@ public static bool InheritsFromOrEquals(this ITypeSymbol type, ITypeSymbol baseT return false; } - public static bool InheritsFrom(this ITypeSymbol type, Type baseType) + internal static bool InheritsFrom(this ITypeSymbol type, Type baseType) { foreach (var t in type.GetBaseTypesAndThis()) { diff --git a/src/Utility.cs b/src/Utility.cs index d18d80a..e720c05 100644 --- a/src/Utility.cs +++ b/src/Utility.cs @@ -6,11 +6,7 @@ namespace FUICompiler { public static class Utility { - public static string ObservableObjectFullName = "FUI.ObservableObjectAttribute"; - public static string ObservablePropertyFullName = "FUI.ObservablePropertyAttribute"; - public static string SynchronizePropertiesFullName = "FUI.ISynchronizeProperties"; - public static string SynchronizePropertiesMethodName = "Synchronize"; - public static string BindingConfigFullName = "FUI.BindingAttribute"; + public const string BindingContextDefaultNamespace = "__DataBindingGenerated"; public static string FileHead = @" //This file was generated by FUICompiler @@ -74,162 +70,6 @@ public static string GetPropertyBackingFieldName(string propertyName) return $"_{propertyName}_BackingField"; } - /// - /// 可观察对象基类类型名 - /// - static string[] ObservableObjectBaseTypes = new string[] - { - "ObservableObject", - "Bindable.ObservableObject", - "FUI.Bindable.ObservableObject", - "ViewModel", - "FUI.ViewModel", - }; - - /// - /// 可观察对象特性名 - /// - static string[] ObservableObjectAttributes = new string[] - { - "ObservableObject", - "FUI.ObservableObject", - "ObservableObjectAttribute", - "FUI.ObservableObjectAttribute", - - "Binding", - "BindingAttribute", - "FUI.Binding", - "FUI.BindingAttribute" - }; - - /// - /// 是否是可观察对象 - /// - /// 类型定义 - /// - public static bool IsObservableObject(ClassDeclarationSyntax classDeclaration) - { - //基类不为空 - if (classDeclaration.BaseList != null) - { - foreach (var baseType in classDeclaration.BaseList.Types) - { - if (ObservableObjectBaseTypes.Contains(baseType.Type.ToString())) - { - return true; - } - } - }; - - //特性不为空 - if (classDeclaration.AttributeLists != null) - { - foreach (var att in classDeclaration.AttributeLists) - { - foreach (var node in att.ChildNodes().OfType()) - { - foreach (var id in node.ChildNodes().OfType()) - { - if (ObservableObjectAttributes.Contains(id.ToString())) - { - return true; - } - } - } - } - } - - return false; - } - - /// - /// 可绑定属性特性名 - /// - static string[] ObservablePropertyAttributes = new string[] - { - "ObservableProperty", - "ObservablePropertyAttribute", - "FUI.ObservableProperty", - "FUI.ObservablePropertyAttribute", - - "Binding", - "BindingAttribute", - "FUI.Binding", - "FUI.BindingAttribute" - }; - - /// - /// 可绑定属性忽略特性名 - /// - static string[] ObservablePropertyIgnoreAttributes = new string[] - { - "ObservablePropertyIgnore", - "ObservablePropertyIgnoreAttribute", - "FUI.ObservablePropertyIgnore", - "FUI.ObservablePropertyIgnoreAttribute" - }; - - /// - /// 判断是一个属性是否是可观察属性 - /// - /// - /// - /// - public static bool IsObservableProperty(ClassDeclarationSyntax clazz, PropertyDeclarationSyntax propertyDeclaration) - { - if (!IsObservableObject(clazz)) - { - return false; - } - - var propertyAttributes = propertyDeclaration.AttributeLists.ToList(); - foreach (var att in propertyAttributes) - { - foreach (var node in att.ChildNodes().OfType()) - { - foreach (var id in node.ChildNodes().OfType()) - { - if (ObservablePropertyIgnoreAttributes.Contains(id.ToString())) - { - return false; - } - } - } - } - return true; - } - - /// - /// 可绑定属性忽略特性名 - /// - static string[] ObservableListTypeNames = new string[] - { - "ObservableList", - "FUI.ObservableList", - }; - - /// - /// 判断一个属性是否是可观察列表 - /// - /// - /// - /// - public static bool IsObservableList(ClassDeclarationSyntax clazz, PropertyDeclarationSyntax propertyDeclaration) - { - if (!IsObservableProperty(clazz, propertyDeclaration)) - { - return false; - } - - var propertyType = propertyDeclaration.Type; - if (!(propertyType is GenericNameSyntax genericName)) - { - return false; - } - - return ObservableListTypeNames.Contains(genericName.Identifier.Text); - } - /// /// 通过特性绑定的特性名 /// @@ -342,28 +182,6 @@ public static string GetEventMethodName(string eventName) return $"__EventMethod_{eventName}"; } - /// - /// 尝试获取命名空间 - /// - /// 类定义 - /// 命名空间名 - /// - public static bool TryGetNamespace(ClassDeclarationSyntax classDeclaration, out string namespaceName) - { - namespaceName = null; - var parent = classDeclaration.Parent; - while (parent != null) - { - if (parent is NamespaceDeclarationSyntax namespaceDeclaration) - { - namespaceName = namespaceDeclaration.Name.ToString(); - return true; - } - parent = parent.Parent; - } - return false; - } - /// /// 获取或者创建一个文件夹 /// @@ -384,7 +202,6 @@ public static DirectoryInfo GetOrCreateDirectory(string path) /// /// 获取绑定上下文类型名 /// - /// 命名空间全称 /// 上下文信息 /// public static string GetBindingContextTypeName(ContextBindingInfo contextInfo) @@ -392,6 +209,16 @@ public static string GetBindingContextTypeName(ContextBindingInfo contextInfo) return $"{contextInfo.viewModelType.ToCSharpName()}_{contextInfo.viewName}_Binding_Generated"; } + /// + /// 获取绑定上下文类型全称 + /// + /// 上下文信息 + /// + public static string GetBindingContextTypeFullName(ContextBindingInfo contextInfo) + { + return $"{BindingContextDefaultNamespace}.{GetBindingContextTypeName(contextInfo)}"; + } + /// /// 转换成位置信息 ///