mirror of
https://github.com/ShrlAlgo/RevitGen.git
synced 2026-03-07 17:28:54 +00:00
添加项目文件。
This commit is contained in:
13
RevitGen.Common/Attributes/CommandHandlerAttribute.cs
Normal file
13
RevitGen.Common/Attributes/CommandHandlerAttribute.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace RevitGen.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// 标记一个方法作为 RevitGen 命令的执行逻辑入口点。
|
||||
/// ★★ 这个方法必须是无参数的,并且返回 void。★★
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class CommandHandlerAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
56
RevitGen.Common/Attributes/RevitCommandAttribute.cs
Normal file
56
RevitGen.Common/Attributes/RevitCommandAttribute.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
// RevitGen.Common/Attributes/RevitCommandAttribute.cs
|
||||
|
||||
using System;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
|
||||
namespace RevitGen.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// 将一个类标记为Revit外部命令,并自动为其生成UI按钮和必要的接口实现。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class RevitCommandAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 按钮上显示的文本。
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 按钮所在的Ribbon Tab的名称。
|
||||
/// </summary>
|
||||
public string TabName { get; set; } = "RevitGen";
|
||||
|
||||
/// <summary>
|
||||
/// 按钮所在的Ribbon Panel的名称。
|
||||
/// </summary>
|
||||
public string PanelName { get; set; } = "Commands";
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string Icon { get; set; } = "";
|
||||
/// <summary>
|
||||
/// 鼠标悬停在按钮上时显示的工具提示。
|
||||
/// </summary>
|
||||
public string ToolTip { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 命令的事务模式。生成器将根据此模式自动处理事务。
|
||||
/// </summary>
|
||||
public TransactionMode TransactionMode { get; set; } = TransactionMode.Manual;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="text">按钮上显示的文本。</param>
|
||||
public RevitCommandAttribute(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(text), "Command button text cannot be empty.");
|
||||
}
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
RevitGen.Common/RevitGen.Common.csproj
Normal file
14
RevitGen.Common/RevitGen.Common.csproj
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- 定义你的包信息 -->
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<!-- 在这里添加或修改 NoWarn 标签 -->
|
||||
<NoWarn>$(NoWarn);NU1701</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nice3point.Revit.Api.RevitAPI" Version="2020.2.60" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
102
RevitGen.Generator/RevitCommandGenerator.cs
Normal file
102
RevitGen.Generator/RevitCommandGenerator.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace RevitGen.Generator
|
||||
{
|
||||
[Generator(LanguageNames.CSharp)]
|
||||
public class RevitCommandGenerator : ISourceGenerator
|
||||
{
|
||||
// ★★ 1. 修正常量,使用 RevitCommandAttribute ★★
|
||||
private const string RevitCommandAttributeFullName = "RevitGen.Attributes.RevitCommandAttribute";
|
||||
private const string CommandHandlerAttributeFullName = "RevitGen.Attributes.CommandHandlerAttribute";
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var log = new StringBuilder();
|
||||
log.AppendLine("// RevitGen Log:");
|
||||
log.AppendLine($"// Compilation assembly: {context.Compilation.AssemblyName}");
|
||||
|
||||
if (!(context.SyntaxReceiver is SyntaxReceiver receiver))
|
||||
{
|
||||
// ... [日志和返回逻辑不变] ...
|
||||
return;
|
||||
}
|
||||
|
||||
log.AppendLine($"// Candidate classes found by SyntaxReceiver: {receiver.CandidateClasses.Count}");
|
||||
if (receiver.CandidateClasses.Count == 0)
|
||||
{
|
||||
// ... [日志和返回逻辑不变] ...
|
||||
return;
|
||||
}
|
||||
|
||||
// ★★ 2. 确保我们查找的是正确的特性符号 ★★
|
||||
var attributeSymbol = context.Compilation.GetTypeByMetadataName(RevitCommandAttributeFullName);
|
||||
if (attributeSymbol == null)
|
||||
{
|
||||
log.AppendLine($"// ERROR: Could not find attribute symbol: {RevitCommandAttributeFullName}");
|
||||
AddSource(context, "RevitGen_Debug_Log.g.cs", log.ToString());
|
||||
return;
|
||||
}
|
||||
log.AppendLine($"// Successfully found attribute symbol: {attributeSymbol.Name}");
|
||||
|
||||
var commandClasses = new List<INamedTypeSymbol>();
|
||||
foreach (var candidateClass in receiver.CandidateClasses)
|
||||
{
|
||||
log.AppendLine($"// -> Processing candidate: {candidateClass.Identifier.ValueText}");
|
||||
var model = context.Compilation.GetSemanticModel(candidateClass.SyntaxTree);
|
||||
var classSymbol = model.GetDeclaredSymbol(candidateClass) as INamedTypeSymbol;
|
||||
|
||||
if (classSymbol == null)
|
||||
{
|
||||
log.AppendLine($"// -> SKIPPED: Could not get class symbol.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// ★★ 3. 检查是否应用了正确的 [RevitCommand] 特性 ★★
|
||||
bool hasAttribute = classSymbol.GetAttributes().Any(ad =>
|
||||
ad.AttributeClass?.Equals(attributeSymbol, SymbolEqualityComparer.Default) ?? false);
|
||||
|
||||
if (hasAttribute)
|
||||
{
|
||||
log.AppendLine($"// -> SUCCESS: Found [RevitCommand] attribute. Adding to list.");
|
||||
commandClasses.Add(classSymbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.AppendLine($"// -> SKIPPED: Did not find [RevitCommand] attribute.");
|
||||
}
|
||||
}
|
||||
|
||||
log.AppendLine($"// Total command classes to generate: {commandClasses.Count}");
|
||||
|
||||
if (commandClasses.Any())
|
||||
{
|
||||
// ... [生成 partial 类和 App 类的逻辑不变] ...
|
||||
foreach (var classSymbol in commandClasses)
|
||||
{
|
||||
var partialClassSource = SourceGenerationHelper.GenerateCommandPartialClass(classSymbol);
|
||||
AddSource(context, $"{classSymbol.Name}.g.cs", partialClassSource);
|
||||
}
|
||||
|
||||
var appSource = SourceGenerationHelper.GenerateApplicationClass(commandClasses);
|
||||
AddSource(context, "RevitGenApplication.g.cs", appSource);
|
||||
}
|
||||
|
||||
AddSource(context, "RevitGen_Debug_Log.g.cs", log.ToString());
|
||||
}
|
||||
|
||||
private void AddSource(GeneratorExecutionContext context, string hintName, string source)
|
||||
{
|
||||
context.AddSource(hintName, SourceText.From(source, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
||||
18
RevitGen.Generator/RevitGen.Generator.csproj
Normal file
18
RevitGen.Generator/RevitGen.Generator.csproj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- 标准引用,用于写代码 -->
|
||||
<ProjectReference Include="..\RevitGen.Common\RevitGen.Common.csproj" />
|
||||
|
||||
<!-- 分析器引用,用于代码生成 -->
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
279
RevitGen.Generator/SourceGenerationHelper.cs
Normal file
279
RevitGen.Generator/SourceGenerationHelper.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RevitGen.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// 一个静态辅助类,包含了所有用于生成C#源代码的逻辑。
|
||||
/// </summary>
|
||||
internal static class SourceGenerationHelper
|
||||
{
|
||||
// 定义我们属性的完整名称,以使用最终确定的、正确的命名方案。
|
||||
private const string RevitCommandAttributeFullName = "RevitGen.Attributes.RevitCommandAttribute";
|
||||
private const string CommandHandlerAttributeFullName = "RevitGen.Attributes.CommandHandlerAttribute";
|
||||
|
||||
/// <summary>
|
||||
/// 为一个具体的命令生成其 partial class 的【另一半】。
|
||||
/// 这一半会实现 IExternalCommand 并提供所有上下文属性。
|
||||
/// </summary>
|
||||
public static string GenerateCommandPartialClass(INamedTypeSymbol classSymbol)
|
||||
{
|
||||
var ns = classSymbol.ContainingNamespace.ToDisplayString();
|
||||
var className = classSymbol.Name;
|
||||
|
||||
var commandHandlerMethod = classSymbol.GetMembers()
|
||||
.OfType<IMethodSymbol>()
|
||||
.FirstOrDefault(m => m.GetAttributes().Any(a => a.AttributeClass?.ToDisplayString() == CommandHandlerAttributeFullName));
|
||||
|
||||
if (commandHandlerMethod == null || commandHandlerMethod.Parameters.Any() || !commandHandlerMethod.ReturnsVoid)
|
||||
{
|
||||
return $"// 错误({className}): 必须有一个被[CommandHandler]标记的、无参数且返回void的方法。";
|
||||
}
|
||||
|
||||
var attributeData = classSymbol.GetAttributes().First(ad => ad.AttributeClass?.ToDisplayString() == RevitCommandAttributeFullName);
|
||||
var transactionMode = GetAttributeProperty(attributeData, "TransactionMode", 1);
|
||||
|
||||
var source = new StringBuilder();
|
||||
source.AppendLine("// <auto-generated/>");
|
||||
source.AppendLine($"namespace {ns}");
|
||||
source.AppendLine("{");
|
||||
source.AppendLine(" using Autodesk.Revit.DB;");
|
||||
source.AppendLine(" using Autodesk.Revit.UI;");
|
||||
source.AppendLine(" using Autodesk.Revit.Attributes;");
|
||||
source.AppendLine(" using System.ComponentModel;");
|
||||
source.AppendLine();
|
||||
|
||||
source.AppendLine($" [Transaction((TransactionMode){transactionMode})]");
|
||||
source.AppendLine($" public partial class {className} : IExternalCommand");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" private ExternalCommandData _commandData;");
|
||||
source.AppendLine(" public UIApplication UIApplication => _commandData.Application;");
|
||||
source.AppendLine(" public UIDocument UIDocument => UIApplication.ActiveUIDocument;");
|
||||
source.AppendLine(" public Document Document => UIDocument.Document;");
|
||||
source.AppendLine(" public View ActiveView => UIDocument.ActiveView;");
|
||||
source.AppendLine(" public Result Result { get; set; } = Result.Succeeded;");
|
||||
source.AppendLine(" public string ErrorMessage { get; set; } = string.Empty;");
|
||||
source.AppendLine(" public ElementSet ElementSet { get; private set; }");
|
||||
source.AppendLine();
|
||||
|
||||
source.AppendLine(" public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" this._commandData = commandData;");
|
||||
source.AppendLine(" this.ElementSet = elements;");
|
||||
source.AppendLine();
|
||||
source.AppendLine(" try");
|
||||
source.AppendLine(" {");
|
||||
if (transactionMode == 1)
|
||||
{
|
||||
source.AppendLine($" using (var trans = new Transaction(this.Document, \"{className}\"))");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" trans.Start();");
|
||||
source.AppendLine($" this.{commandHandlerMethod.Name}();");
|
||||
source.AppendLine(" if (this.Result == Result.Succeeded) trans.Commit(); else trans.RollBack();");
|
||||
source.AppendLine(" }");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine($" this.{commandHandlerMethod.Name}();");
|
||||
}
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" catch (System.Exception ex)");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" this.ErrorMessage = ex.ToString();");
|
||||
source.AppendLine(" this.Result = Result.Failed;");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine();
|
||||
source.AppendLine(" message = this.ErrorMessage;");
|
||||
source.AppendLine(" return this.Result;");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine("}");
|
||||
return source.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成唯一的 IExternalApplication 类,用于创建Revit界面 (选项卡, 面板, 按钮)。
|
||||
/// </summary>
|
||||
public static string GenerateApplicationClass(IEnumerable<INamedTypeSymbol> commandClasses)
|
||||
{
|
||||
var source = new StringBuilder();
|
||||
source.AppendLine("// <auto-generated/>");
|
||||
source.AppendLine("using Autodesk.Revit.UI;");
|
||||
source.AppendLine("using System;");
|
||||
source.AppendLine("using System.Reflection;");
|
||||
source.AppendLine("using System.Windows.Media;");
|
||||
source.AppendLine("using System.Windows.Media.Imaging;");
|
||||
source.AppendLine("using System.IO;");
|
||||
source.AppendLine("using System.Drawing;");
|
||||
source.AppendLine("using System.Resources;");
|
||||
|
||||
source.AppendLine();
|
||||
source.AppendLine("namespace RevitGen.Runtime");
|
||||
source.AppendLine("{");
|
||||
source.AppendLine(" public class RevitGenApplication : IExternalApplication");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" private static ResourceManager _resourceManager;");
|
||||
|
||||
source.AppendLine(" private BitmapSource BitmapToImageSource(Bitmap bitmap)");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" if (bitmap == null) return null;");
|
||||
source.AppendLine(" using (MemoryStream stream = new MemoryStream())");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);");
|
||||
source.AppendLine(" stream.Position = 0;");
|
||||
source.AppendLine(" BitmapImage result = new BitmapImage();");
|
||||
source.AppendLine(" result.BeginInit();");
|
||||
source.AppendLine(" result.CacheOption = BitmapCacheOption.OnLoad;");
|
||||
source.AppendLine(" result.StreamSource = stream;");
|
||||
source.AppendLine(" result.EndInit();");
|
||||
source.AppendLine(" result.Freeze();");
|
||||
source.AppendLine(" return result;");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine();
|
||||
|
||||
source.AppendLine(" private BitmapSource LoadImageFromEmbeddedResource(Assembly assembly, string resourcePath)");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" try");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" string assemblyName = assembly.GetName().Name;");
|
||||
source.AppendLine(" string resourceName = $\"{assemblyName}.{resourcePath.Replace('/', '.').Replace('\\\\', '.')}\";");
|
||||
source.AppendLine(" using (Stream stream = assembly.GetManifestResourceStream(resourceName))");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" if (stream == null) return null;");
|
||||
source.AppendLine(" var image = new BitmapImage();");
|
||||
source.AppendLine(" image.BeginInit();");
|
||||
source.AppendLine(" image.StreamSource = stream;");
|
||||
source.AppendLine(" image.CacheOption = BitmapCacheOption.OnLoad;");
|
||||
source.AppendLine(" image.EndInit();");
|
||||
source.AppendLine(" image.Freeze();");
|
||||
source.AppendLine(" return image;");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" catch { return null; }");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine();
|
||||
|
||||
source.AppendLine(" public Result OnStartup(UIControlledApplication app)");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" var assembly = Assembly.GetExecutingAssembly();");
|
||||
source.AppendLine(" string assemblyPath = assembly.Location;");
|
||||
|
||||
source.AppendLine(" if (_resourceManager == null)");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine(" string resourceName = assembly.GetName().Name + \".Properties.Resources\";");
|
||||
source.AppendLine(" try { _resourceManager = new ResourceManager(resourceName, assembly); } catch { /* ResX 不存在时忽略 */ }");
|
||||
source.AppendLine(" }");
|
||||
|
||||
source.AppendLine();
|
||||
|
||||
var commandsWithData = commandClasses.Select(c => new {
|
||||
Symbol = c,
|
||||
Attribute = c.GetAttributes().First(ad => ad.AttributeClass?.ToDisplayString() == RevitCommandAttributeFullName)
|
||||
}).ToList();
|
||||
|
||||
var groupedByTab = commandsWithData.GroupBy(data => GetAttributeProperty<string>(data.Attribute, "TabName", null));
|
||||
|
||||
foreach (var tabGroup in groupedByTab)
|
||||
{
|
||||
var tabName = tabGroup.Key;
|
||||
|
||||
if (!string.IsNullOrEmpty(tabName))
|
||||
{
|
||||
source.AppendLine($" try {{ app.CreateRibbonTab(\"{tabName}\"); }} catch {{ /* 选项卡已存在 */ }}");
|
||||
}
|
||||
|
||||
var groupedByPanel = tabGroup.GroupBy(data => GetAttributeProperty(data.Attribute, "PanelName", "Commands"));
|
||||
foreach (var panelGroup in groupedByPanel)
|
||||
{
|
||||
var panelName = panelGroup.Key;
|
||||
var panelVar = $"panel_{SanitizeIdentifier(tabName ?? "AddIns")}_{SanitizeIdentifier(panelName)}";
|
||||
|
||||
if (!string.IsNullOrEmpty(tabName))
|
||||
{
|
||||
source.AppendLine($" RibbonPanel {panelVar} = app.CreateRibbonPanel(\"{tabName}\", \"{panelName}\");");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine($" RibbonPanel {panelVar} = app.CreateRibbonPanel(\"{panelName}\");");
|
||||
}
|
||||
|
||||
foreach (var commandData in panelGroup)
|
||||
{
|
||||
var commandSymbol = commandData.Symbol;
|
||||
var attr = commandData.Attribute;
|
||||
var buttonText = (string)attr.ConstructorArguments.First().Value;
|
||||
var fullClassName = commandSymbol.ToDisplayString();
|
||||
var iconName = GetAttributeProperty(attr, "Icon", string.Empty);
|
||||
var tooltip = GetAttributeProperty(attr, "ToolTip", string.Empty);
|
||||
|
||||
source.AppendLine($" var pbd_{commandSymbol.Name} = new PushButtonData(\"cmd_{commandSymbol.Name}\", \"{buttonText}\", assemblyPath, \"{fullClassName}\");");
|
||||
|
||||
if (!string.IsNullOrEmpty(tooltip))
|
||||
{
|
||||
source.AppendLine($" pbd_{commandSymbol.Name}.ToolTip = \"{tooltip}\";");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(iconName))
|
||||
{
|
||||
// ★★ 核心修正:为每个按钮的图标处理逻辑创建一个独立的局部作用域 ★★
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine($" string iconExtension = System.IO.Path.GetExtension(\"{iconName}\");");
|
||||
source.AppendLine(" if (!string.IsNullOrEmpty(iconExtension))");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine($" pbd_{commandSymbol.Name}.LargeImage = LoadImageFromEmbeddedResource(assembly, \"{iconName}\");");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" else");
|
||||
source.AppendLine(" {");
|
||||
source.AppendLine($" if (_resourceManager != null)");
|
||||
source.AppendLine($" {{");
|
||||
source.AppendLine($" try");
|
||||
source.AppendLine($" {{");
|
||||
source.AppendLine($" var iconBitmap = (Bitmap)_resourceManager.GetObject(\"{iconName}\");");
|
||||
source.AppendLine($" pbd_{commandSymbol.Name}.LargeImage = BitmapToImageSource(iconBitmap);");
|
||||
source.AppendLine($" }}");
|
||||
source.AppendLine($" catch {{ /* 资源未找到或加载失败 */ }}");
|
||||
source.AppendLine($" }}");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" }"); // ★★ 结束局部作用域 ★★
|
||||
}
|
||||
|
||||
source.AppendLine($" {panelVar}.AddItem(pbd_{commandSymbol.Name});");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source.AppendLine(" return Result.Succeeded;");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine(" public Result OnShutdown(UIControlledApplication app) => Result.Succeeded;");
|
||||
source.AppendLine(" }");
|
||||
source.AppendLine("}");
|
||||
return source.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一个辅助方法,用于从特性的数据中安全地读取一个具名属性。
|
||||
/// </summary>
|
||||
private static T GetAttributeProperty<T>(AttributeData attributeData, string propertyName, T defaultValue)
|
||||
{
|
||||
var namedArgument = attributeData.NamedArguments.FirstOrDefault(kvp => kvp.Key == propertyName);
|
||||
if (namedArgument.Value.Value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return (T)namedArgument.Value.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一个辅助方法,用于清理字符串,使其可以用作C#变量名。
|
||||
/// </summary>
|
||||
private static string SanitizeIdentifier(string name)
|
||||
{
|
||||
return Regex.Replace(name, @"[^\w]", "_");
|
||||
}
|
||||
}
|
||||
}
|
||||
40
RevitGen.Generator/SyntaxReceiver.cs
Normal file
40
RevitGen.Generator/SyntaxReceiver.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// RevitGen.Generator/SyntaxReceiver.cs
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RevitGen.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// 在语法树中查找所有带有属性的、定义为 partial 的类,作为代码生成的候选对象。
|
||||
/// </summary>
|
||||
internal class SyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public List<ClassDeclarationSyntax> CandidateClasses { get; } = new List<ClassDeclarationSyntax>();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
// 检查节点是否是一个类声明,并且它带有属性
|
||||
//if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax &&
|
||||
// classDeclarationSyntax.AttributeLists.Count > 0)
|
||||
//{
|
||||
// // 检查类是否被声明为 partial
|
||||
// foreach (var modifier in classDeclarationSyntax.Modifiers)
|
||||
// {
|
||||
// if (modifier.ValueText == "partial")
|
||||
// {
|
||||
// CandidateClasses.Add(classDeclarationSyntax);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax &&
|
||||
classDeclarationSyntax.AttributeLists.Count > 0)
|
||||
{
|
||||
CandidateClasses.Add(classDeclarationSyntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
RevitGen.sln
Normal file
43
RevitGen.sln
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36414.22 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitGen", "RevitGen\RevitGen.csproj", "{36A67B40-B574-495A-A8EA-ED45B19E2A79}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitGenTest", "RevitGenTest\RevitGenTest.csproj", "{6303F3AA-6ECC-4619-8260-6A87E2BCBD50}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitGen.Generator", "RevitGen.Generator\RevitGen.Generator.csproj", "{01D32114-2908-4AEF-A420-DB3D257A6FDD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitGen.Common", "RevitGen.Common\RevitGen.Common.csproj", "{DFFA8B05-51AE-4A96-834E-726090A329AD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{36A67B40-B574-495A-A8EA-ED45B19E2A79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{36A67B40-B574-495A-A8EA-ED45B19E2A79}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{36A67B40-B574-495A-A8EA-ED45B19E2A79}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{36A67B40-B574-495A-A8EA-ED45B19E2A79}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6303F3AA-6ECC-4619-8260-6A87E2BCBD50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6303F3AA-6ECC-4619-8260-6A87E2BCBD50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6303F3AA-6ECC-4619-8260-6A87E2BCBD50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6303F3AA-6ECC-4619-8260-6A87E2BCBD50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{01D32114-2908-4AEF-A420-DB3D257A6FDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{01D32114-2908-4AEF-A420-DB3D257A6FDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{01D32114-2908-4AEF-A420-DB3D257A6FDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{01D32114-2908-4AEF-A420-DB3D257A6FDD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DFFA8B05-51AE-4A96-834E-726090A329AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DFFA8B05-51AE-4A96-834E-726090A329AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DFFA8B05-51AE-4A96-834E-726090A329AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DFFA8B05-51AE-4A96-834E-726090A329AD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {655FFF69-A9C7-470E-9D97-47894C4DC93D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
35
RevitGen/RevitGen.csproj
Normal file
35
RevitGen/RevitGen.csproj
Normal file
@@ -0,0 +1,35 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- 包信息 -->
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<PackageId>RevitGen</PackageId>
|
||||
<Version>1.0.0</Version>
|
||||
<Authors>ShrlAlgo</Authors>
|
||||
<Description>A powerful source generator to accelerate Revit add-in development.</Description>
|
||||
<PackageTags>Revit;SourceGenerator;CodeGen</PackageTags>
|
||||
|
||||
<!-- 关键设置 -->
|
||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
|
||||
<!-- 将此包标记为纯开发时依赖 -->
|
||||
<DevelopmentDependency>true</DevelopmentDependency>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- 1. 将 Common.dll 打包到 lib/ 目录 -->
|
||||
<None Include="..\RevitGen.Common\bin\$(Configuration)\netstandard2.0\RevitGen.Common.dll" Pack="true" PackagePath="lib\netstandard2.0" />
|
||||
|
||||
<!-- 2. 将 Generator.dll 打包到 analyzers/ 目录 -->
|
||||
<None Include="..\RevitGen.Generator\bin\$(Configuration)\netstandard2.0\RevitGen.Generator.dll" Pack="true" PackagePath="analyzers\dotnet\cs" />
|
||||
|
||||
<!--
|
||||
我们仍然保留 ProjectReference,但它的作用变了:
|
||||
它不再负责打包,而是只负责【确保正确的编译顺序】。
|
||||
`ReferenceOutputAssembly="false"` 可以防止循环依赖。
|
||||
-->
|
||||
<ProjectReference Include="..\RevitGen.Common\RevitGen.Common.csproj" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\RevitGen.Generator\RevitGen.Generator.csproj" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
83
RevitGenTest/Properties/Resources.Designer.cs
generated
Normal file
83
RevitGenTest/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,83 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RevitGenTest.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevitGenTest.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap CodeList_16px {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("CodeList_16px", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap CodeList_32px {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("CodeList_32px", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
RevitGenTest/Properties/Resources.resx
Normal file
127
RevitGenTest/Properties/Resources.resx
Normal file
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="CodeList_16px" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CodeList_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CodeList_32px" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CodeList_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
RevitGenTest/Resources/CodeList_16px.png
Normal file
BIN
RevitGenTest/Resources/CodeList_16px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 307 B |
BIN
RevitGenTest/Resources/CodeList_32px.png
Normal file
BIN
RevitGenTest/Resources/CodeList_32px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 498 B |
59
RevitGenTest/RevitAddin.cs
Normal file
59
RevitGenTest/RevitAddin.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using RevitGen.Attributes;
|
||||
|
||||
using RevitGenTest.Properties;
|
||||
|
||||
namespace RevitGenTest
|
||||
{
|
||||
[RevitCommand("我的第一个命令", ToolTip = "这是一个自动生成的酷炫命令!", PanelName = "核心功能", Icon = nameof(Resources.CodeList_32px))]
|
||||
public partial class RevitAddin
|
||||
{
|
||||
[CommandHandler]
|
||||
private void Run()
|
||||
{
|
||||
var walls = new FilteredElementCollector(Document)
|
||||
.OfCategory(BuiltInCategory.OST_Walls)
|
||||
.WhereElementIsNotElementType()
|
||||
.ToElements();
|
||||
|
||||
if (walls.Count == 0)
|
||||
{
|
||||
// 如果出现问题,只需设置属性即可
|
||||
this.ErrorMessage = "项目中没有找到任何墙。";
|
||||
this.Result = Result.Failed;
|
||||
return; // 提前返回
|
||||
}
|
||||
|
||||
TaskDialog.Show("成功", $"找到了 {walls.Count} 面墙。");
|
||||
}
|
||||
}
|
||||
[RevitCommand("我的第一个命令", ToolTip = "这是一个自动生成的酷炫命令!", PanelName = "核心功能", Icon = "Resources/CodeList_32px.png")]
|
||||
public partial class RevitAddinX
|
||||
{
|
||||
[CommandHandler]
|
||||
private void Run()
|
||||
{
|
||||
var walls = new FilteredElementCollector(Document)
|
||||
.OfCategory(BuiltInCategory.OST_Walls)
|
||||
.WhereElementIsNotElementType()
|
||||
.ToElements();
|
||||
|
||||
if (walls.Count == 0)
|
||||
{
|
||||
// 如果出现问题,只需设置属性即可
|
||||
this.ErrorMessage = "项目中没有找到任何墙。";
|
||||
this.Result = Result.Failed;
|
||||
return; // 提前返回
|
||||
}
|
||||
|
||||
TaskDialog.Show("成功", $"找到了 {walls.Count} 面墙。");
|
||||
}
|
||||
}
|
||||
}
|
||||
33
RevitGenTest/RevitGenTest.csproj
Normal file
33
RevitGenTest/RevitGenTest.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<UseWPF>True</UseWPF>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\CodeList_32px.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\CodeList_32px.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<PackageReference Include="Nice3point.Revit.Api.RevitAPI" Version="2020.2.60" />
|
||||
<PackageReference Include="Nice3point.Revit.Api.RevitAPIUI" Version="2020.2.60" />
|
||||
<PackageReference Include="RevitGen" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
11
nuget.config
Normal file
11
nuget.config
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<!-- 清除所有继承的源,可选,但能保证环境干净 -->
|
||||
<clear />
|
||||
<!-- 添加官方 NuGet 源 -->
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<!-- 添加你的本地包源,路径是包含 .nupkg 文件的文件夹 -->
|
||||
<add key="LocalRevitGenSource" value="./RevitGen/bin/Release" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user