5 Commits

Author SHA1 Message Date
GG Z
c884115bcd 修复字节流加载找不到路径 2026-01-31 21:24:17 +08:00
GG Z
8d800e8927 更新样式 2026-01-23 21:43:46 +08:00
ShrlAlgo
9b7a6e2772 修复无法二次调试 2026-01-23 18:07:21 +08:00
ShrlAlgo
766fa23cc0 命名调整,修复无法调试的问题 2026-01-20 16:03:32 +08:00
GG Z
681681c7ed 修复NullReferenceException 2026-01-16 21:03:48 +08:00
11 changed files with 241 additions and 267 deletions

3
.gitignore vendored
View File

@@ -360,4 +360,5 @@ MigrationBackup/
.ionide/ .ionide/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
/Setup

View File

@@ -36,35 +36,75 @@ namespace AddInManager
private Result RunActiveCommand(ExternalCommandData data, ref string message, ElementSet elements) private Result RunActiveCommand(ExternalCommandData data, ref string message, ElementSet elements)
{ {
// 防御性检查:确保 ActiveCmd 不为空
if (this.ActiveCmd == null)
{
MessageBox.Show("错误ActiveCmd 为 null");
return Result.Failed;
}
// 防御性检查:确保 ActiveCmdItem 不为空
if (this.ActiveCmdItem == null)
{
MessageBox.Show("错误ActiveCmdItem 为 null");
return Result.Failed;
}
var filePath = ActiveCmd.FilePath; var filePath = ActiveCmd.FilePath;
// 检查文件是否存在
if (!System.IO.File.Exists(filePath))
{
MessageBox.Show($"错误:找不到文件 {filePath}");
return Result.Failed;
}
var assemLoader = new AssemLoader(); var assemLoader = new AssemLoader();
Result result; Result result = Result.Failed; // 默认失败
try try
{ {
assemLoader.HookAssemblyResolve(); assemLoader.HookAssemblyResolve();
var assembly = assemLoader.LoadAddinsToTempFolder(filePath, false); var assembly = assemLoader.LoadAddinsToTempFolder(filePath, false);
if (null == assembly)
if (assembly == null)
{ {
message = "Assembly 加载失败,返回了 null";
result = Result.Failed; result = Result.Failed;
} }
else else
{ {
ActiveTempFolder = assemLoader.TempFolder; ActiveTempFolder = assemLoader.TempFolder;
var externalCommand = assembly.CreateInstance(ActiveCmdItem.FullClassName) as IExternalCommand;
if (externalCommand == null) string className = ActiveCmdItem.FullClassName;
if (string.IsNullOrEmpty(className)) throw new Exception("类名为空");
var instanceObj = assembly.CreateInstance(className);
if (instanceObj == null)
{ {
message = $"无法创建实例: {className}。请检查类名是否正确或是否有无参构造函数。";
result = Result.Failed; result = Result.Failed;
} }
else else
{ {
ActiveEC = externalCommand; if (instanceObj is not IExternalCommand externalCommand)
result = ActiveEC.Execute(data, ref message, elements); {
message = $"{className} 没有实现 IExternalCommand 接口";
result = Result.Failed;
}
else
{
ActiveEC = externalCommand;
result = ActiveEC.Execute(data, ref message, elements);
}
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(ex.ToString()); MessageBox.Show($"执行异常:\n{ex.Message}\n\n堆栈:\n{ex.StackTrace}");
result = Result.Failed; result = Result.Failed;
} }
finally finally

View File

@@ -42,7 +42,7 @@ namespace AddInManager
} }
} }
public void SaveToLocalIni(IniFile file) public void SaveToLocalIni(InitFile file)
{ {
if (ItemList == null || ItemList.Count == 0) if (ItemList == null || ItemList.Count == 0)
{ {
@@ -74,7 +74,7 @@ namespace AddInManager
file.Write("ExternalApplications", "EACount", num2); file.Write("ExternalApplications", "EACount", num2);
} }
private void WriteExternalCommand(IniFile file, AddinItem item, int number) private void WriteExternalCommand(InitFile file, AddinItem item, int number)
{ {
file.Write("ExternalCommands", $"ECName{number}", item.Name); file.Write("ExternalCommands", $"ECName{number}", item.Name);
file.Write("ExternalCommands", $"ECClassName{number}", item.FullClassName); file.Write("ExternalCommands", $"ECClassName{number}", item.FullClassName);
@@ -82,7 +82,7 @@ namespace AddInManager
file.Write("ExternalCommands", $"ECDescription{number}", item.Description); file.Write("ExternalCommands", $"ECDescription{number}", item.Description);
} }
private void WriteExternalApplication(IniFile file, AddinItem item, int number) private void WriteExternalApplication(InitFile file, AddinItem item, int number)
{ {
file.Write("ExternalApplications", $"EAClassName{number}", item.FullClassName); file.Write("ExternalApplications", $"EAClassName{number}", item.FullClassName);
file.Write("ExternalApplications", $"EAAssembly{number}", item.AssemblyName); file.Write("ExternalApplications", $"EAAssembly{number}", item.AssemblyName);

View File

@@ -28,34 +28,27 @@ namespace AddInManager
ReadAddinsFromAimIni(); ReadAddinsFromAimIni();
} }
public IniFile AimIniFile { get; set; } public InitFile AimJsonFile { get; set; }
public IniFile RevitIniFile { get; set; } public InitFile RevitIniFile { get; set; }
private void GetIniFilePaths() private void GetIniFilePaths()
{ {
//var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); //var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var appFolder = Path.Combine(folderPath, Resources.AppFolder); var appFolder = Path.Combine(folderPath, Resources.AppFolder);
// switch from INI to JSON storage var jsonFilePath = Path.Combine(appFolder, "AimInternal.json");
var iniFilePath = Path.Combine(appFolder, "AimInternal.json"); AimJsonFile = new InitFile(jsonFilePath);
AimIniFile = new IniFile(iniFilePath);
// If an old INI exists, migrate it to JSON (one-time)
try try
{ {
var oldIniPath = Path.Combine(appFolder, "AimInternal.ini"); var oldIniPath = Path.Combine(appFolder, "AimInternal.ini");
if (File.Exists(oldIniPath) && !File.Exists(iniFilePath)) if (File.Exists(oldIniPath) && !File.Exists(jsonFilePath))
{ {
var oldIni = new IniFile(oldIniPath); var oldIni = new InitFile(oldIniPath);
// populate commands/applications from old INI
Commands.ReadItems(oldIni); Commands.ReadItems(oldIni);
Applications.ReadItems(oldIni); Applications.ReadItems(oldIni);
// save to new JSON store SaveToPersistentStore(jsonFilePath);
SaveToPersistentStore(iniFilePath);
// backup old INI
try try
{ {
var backupPath = oldIniPath + ".bak"; var backupPath = oldIniPath + ".bak";
@@ -77,16 +70,15 @@ namespace AddInManager
var currentProcess = Process.GetCurrentProcess(); var currentProcess = Process.GetCurrentProcess();
var fileName = currentProcess.MainModule.FileName; var fileName = currentProcess.MainModule.FileName;
var revitIniFilePath = fileName.Replace(".exe", ".ini"); var revitIniFilePath = fileName.Replace(".exe", ".ini");
RevitIniFile = new IniFile(revitIniFilePath); RevitIniFile = new InitFile(revitIniFilePath);
} }
public void ReadAddinsFromAimIni() public void ReadAddinsFromAimIni()
{ {
// try load from persistent JSON store; if fails, fall back to legacy INI-format reader if (!LoadFromPersistentStore(AimJsonFile.FilePath))
if (!LoadFromPersistentStore(AimIniFile.FilePath))
{ {
Commands.ReadItems(AimIniFile); Commands.ReadItems(AimJsonFile);
Applications.ReadItems(AimIniFile); Applications.ReadItems(AimJsonFile);
} }
} }
@@ -152,11 +144,11 @@ namespace AddInManager
// ensure file exists // ensure file exists
try try
{ {
if (!File.Exists(AimIniFile.FilePath)) if (!File.Exists(AimJsonFile.FilePath))
{ {
new FileInfo(AimIniFile.FilePath).Directory?.Create(); new FileInfo(AimJsonFile.FilePath).Directory?.Create();
FileUtils.CreateFile(AimIniFile.FilePath); FileUtils.CreateFile(AimJsonFile.FilePath);
FileUtils.SetWriteable(AimIniFile.FilePath); FileUtils.SetWriteable(AimJsonFile.FilePath);
} }
} }
catch (Exception) catch (Exception)
@@ -165,10 +157,10 @@ namespace AddInManager
} }
// save to persistent JSON store; if fails, fall back to legacy INI writer // save to persistent JSON store; if fails, fall back to legacy INI writer
if (!SaveToPersistentStore(AimIniFile.FilePath)) if (!SaveToPersistentStore(AimJsonFile.FilePath))
{ {
Commands.Save(AimIniFile); Commands.Save(AimJsonFile);
Applications.Save(AimIniFile); Applications.Save(AimJsonFile);
} }
} }

View File

@@ -2,7 +2,7 @@
{ {
public class AddinsApplication : Addins public class AddinsApplication : Addins
{ {
public void ReadItems(IniFile file) public void ReadItems(InitFile file)
{ {
var num = file.ReadInt("ExternalApplications", "EACount"); var num = file.ReadInt("ExternalApplications", "EACount");
var i = 1; var i = 1;
@@ -13,7 +13,7 @@
SortAddin(); SortAddin();
} }
private bool ReadExternalApplication(IniFile file, int nodeNumber) private bool ReadExternalApplication(InitFile file, int nodeNumber)
{ {
var text = file.ReadString("ExternalApplications", $"EAClassName{nodeNumber}"); var text = file.ReadString("ExternalApplications", $"EAClassName{nodeNumber}");
var text2 = file.ReadString("ExternalApplications", $"EAAssembly{nodeNumber}"); var text2 = file.ReadString("ExternalApplications", $"EAAssembly{nodeNumber}");
@@ -30,7 +30,7 @@
return true; return true;
} }
public void Save(IniFile file) public void Save(InitFile file)
{ {
file.WriteSection("ExternalApplications"); file.WriteSection("ExternalApplications");
file.Write("ExternalApplications", "EACount", m_maxCount); file.Write("ExternalApplications", "EACount", m_maxCount);
@@ -52,7 +52,7 @@
file.Write("ExternalApplications", "EACount", num); file.Write("ExternalApplications", "EACount", num);
} }
private bool WriteExternalApplication(IniFile file, AddinItem item, int number) private bool WriteExternalApplication(InitFile file, AddinItem item, int number)
{ {
file.Write("ExternalApplications", $"EAClassName{number}", item.FullClassName); file.Write("ExternalApplications", $"EAClassName{number}", item.FullClassName);
file.Write("ExternalApplications", $"EAAssembly{number}", item.AssemblyPath); file.Write("ExternalApplications", $"EAAssembly{number}", item.AssemblyPath);

View File

@@ -2,7 +2,7 @@
{ {
public class AddinsCommand : Addins public class AddinsCommand : Addins
{ {
public void ReadItems(IniFile file) public void ReadItems(InitFile file)
{ {
var num = file.ReadInt("ExternalCommands", "ECCount"); var num = file.ReadInt("ExternalCommands", "ECCount");
var i = 1; var i = 1;
@@ -13,7 +13,7 @@
SortAddin(); SortAddin();
} }
private bool ReadExternalCommand(IniFile file, int nodeNumber) private bool ReadExternalCommand(InitFile file, int nodeNumber)
{ {
var text = file.ReadString("ExternalCommands", $"ECName{nodeNumber}"); var text = file.ReadString("ExternalCommands", $"ECName{nodeNumber}");
var text2 = file.ReadString("ExternalCommands", $"ECAssembly{nodeNumber}"); var text2 = file.ReadString("ExternalCommands", $"ECAssembly{nodeNumber}");
@@ -33,7 +33,7 @@
return true; return true;
} }
public void Save(IniFile file) public void Save(InitFile file)
{ {
file.WriteSection("ExternalCommands"); file.WriteSection("ExternalCommands");
file.Write("ExternalCommands", "ECCount", m_maxCount); file.Write("ExternalCommands", "ECCount", m_maxCount);
@@ -55,7 +55,7 @@
file.Write("ExternalCommands", "ECCount", num); file.Write("ExternalCommands", "ECCount", num);
} }
private bool WriteExternalCommand(IniFile file, AddinItem item, int number) private bool WriteExternalCommand(InitFile file, AddinItem item, int number)
{ {
file.Write("ExternalCommands", $"ECName{number}", item.Name); file.Write("ExternalCommands", $"ECName{number}", item.Name);
file.Write("ExternalCommands", $"ECClassName{number}", item.FullClassName); file.Write("ExternalCommands", $"ECClassName{number}", item.FullClassName);

View File

@@ -17,10 +17,9 @@ namespace AddInManager
private Dictionary<string, DateTime> m_copiedFiles; private Dictionary<string, DateTime> m_copiedFiles;
private bool m_parsingOnly; private bool m_parsingOnly;
// 移除硬编码的 .NET 2.0 路径改用更通用的方式虽然在Revit中通常不依赖这个 // 获取 .NET 运行时目录
private static string m_dotnetDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); private static string m_dotnetDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
public static string m_resolvedAssemPath = string.Empty;
private string m_revitAPIAssemblyFullName; private string m_revitAPIAssemblyFullName;
public AssemLoader() public AssemLoader()
@@ -30,11 +29,10 @@ namespace AddInManager
m_copiedFiles = new Dictionary<string, DateTime>(); m_copiedFiles = new Dictionary<string, DateTime>();
} }
// ... CopyGeneratedFilesBack 保持不变 ... // 保持原有的文件回写逻辑不变
public void CopyGeneratedFilesBack() public void CopyGeneratedFilesBack()
{ {
if (string.IsNullOrEmpty(TempFolder) || !Directory.Exists(TempFolder)) return; if (!Directory.Exists(TempFolder)) return;
var files = Directory.GetFiles(TempFolder, "*.*", SearchOption.AllDirectories); var files = Directory.GetFiles(TempFolder, "*.*", SearchOption.AllDirectories);
foreach (var text in files) foreach (var text in files)
{ {
@@ -49,7 +47,7 @@ namespace AddInManager
FileUtils.CopyFile(text, text3); FileUtils.CopyFile(text, text3);
} }
} }
// 新生成的文件不建议盲目拷回,可能会污染源目录,视需求而定 // 注意:通常我们不希望把临时文件夹产生的所有垃圾文件都拷回源目录,视需求而定
} }
} }
@@ -65,7 +63,7 @@ namespace AddInManager
public Assembly LoadAddinsToTempFolder(string originalFilePath, bool parsingOnly) public Assembly LoadAddinsToTempFolder(string originalFilePath, bool parsingOnly)
{ {
if (string.IsNullOrEmpty(originalFilePath) || originalFilePath.StartsWith("\\") || !File.Exists(originalFilePath)) if (string.IsNullOrEmpty(originalFilePath) || !File.Exists(originalFilePath))
{ {
return null; return null;
} }
@@ -75,12 +73,10 @@ namespace AddInManager
var stringBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(originalFilePath)); var stringBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(originalFilePath));
stringBuilder.Append(parsingOnly ? "-Parsing-" : "-Executing-"); stringBuilder.Append(parsingOnly ? "-Parsing-" : "-Executing-");
// 1. 创建全新的临时文件夹 (基于时间戳,确保唯一)
TempFolder = FileUtils.CreateTempFolder(stringBuilder.ToString()); TempFolder = FileUtils.CreateTempFolder(stringBuilder.ToString());
// 【建议】在此处除了复制主DLL最好把同目录下的所有 .dll 都复制过去 // 2. 复制并加载
// 这样可以避免 AssemblyResolve 频繁触发,解决大部分 NuGet 依赖问题
// CopyAllDllsToTemp(OriginalFolder, TempFolder); // 这是一个建议实现的辅助方法
var assembly = CopyAndLoadAddin(originalFilePath, parsingOnly); var assembly = CopyAndLoadAddin(originalFilePath, parsingOnly);
if (null == assembly || !IsAPIReferenced(assembly)) if (null == assembly || !IsAPIReferenced(assembly))
{ {
@@ -91,7 +87,9 @@ namespace AddInManager
private Assembly CopyAndLoadAddin(string srcFilePath, bool onlyCopyRelated) private Assembly CopyAndLoadAddin(string srcFilePath, bool onlyCopyRelated)
{ {
var destPath = string.Empty; string destPath = string.Empty;
// 复制文件到临时目录
if (!FileUtils.FileExistsInFolder(srcFilePath, TempFolder)) if (!FileUtils.FileExistsInFolder(srcFilePath, TempFolder))
{ {
var directoryName = Path.GetDirectoryName(srcFilePath); var directoryName = Path.GetDirectoryName(srcFilePath);
@@ -99,112 +97,71 @@ namespace AddInManager
{ {
m_refedFolders.Add(directoryName); m_refedFolders.Add(directoryName);
} }
var list = new List<FileInfo>(); var list = new List<FileInfo>();
// 假设 FileUtils.CopyFileToFolder 会处理文件复制
// 关键点:如果你的 FileUtils 不支持复制子文件夹(如 zh-CN资源加载依然会失败
destPath = FileUtils.CopyFileToFolder(srcFilePath, TempFolder, onlyCopyRelated, list); destPath = FileUtils.CopyFileToFolder(srcFilePath, TempFolder, onlyCopyRelated, list);
if (string.IsNullOrEmpty(destPath)) if (string.IsNullOrEmpty(destPath)) return null;
{
return null;
}
foreach (var fileInfo in list) foreach (var fileInfo in list)
{ {
if (!m_copiedFiles.ContainsKey(fileInfo.FullName)) m_copiedFiles[fileInfo.FullName] = fileInfo.LastWriteTime;
m_copiedFiles.Add(fileInfo.FullName, fileInfo.LastWriteTime);
} }
} }
else else
{ {
// 如果文件已存在,计算目标路径 // 如果文件已存在极少情况因为是新Temp目录构造目标路径
string fileName = Path.GetFileName(srcFilePath); destPath = Path.Combine(TempFolder, Path.GetFileName(srcFilePath));
destPath = Path.Combine(TempFolder, fileName);
} }
// 加载复制后的文件
return LoadAddin(destPath); return LoadAddin(destPath);
} }
private Assembly LoadAddin(string filePath) private Assembly LoadAddin(string filePath)
{ {
Assembly assembly = null; Assembly assembly = null;
try try
{ {
Monitor.Enter(this); if (File.Exists(filePath))
// 【关键修改 1】使用 LoadFrom 而不是 LoadFile {
// LoadFrom 会自动在 filePath 所在的目录中查找依赖项,这解决了大部分 NuGet 包加载失败的问题 assembly = Assembly.LoadFrom(filePath);
// LoadFile 这是一个纯粹的文件加载,不带上下文,不会去旁边找依赖 }
assembly = Assembly.LoadFrom(filePath);
} }
catch (Exception ex) catch (Exception ex)
{ {
// 增加简单的错误输出,方便调试
Debug.WriteLine($"LoadAddin Failed: {filePath}, Error: {ex.Message}"); Debug.WriteLine($"LoadAddin Failed: {filePath}, Error: {ex.Message}");
throw; throw;
} }
finally
{
Monitor.Exit(this);
}
return assembly; return assembly;
} }
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{ {
Assembly assembly = null; // 防止递归或死循环
lock (this) string assemblyName = new AssemblyName(args.Name).Name;
// 忽略资源文件
if (assemblyName.EndsWith(".resources") || assemblyName.EndsWith(".XmlSerializers"))
return null;
// 1. 在临时文件夹中寻找依赖项
// 因为主程序是字节流加载的,它不知道自己在 TempFolder必须我们告诉它去那里找
string foundPath = SearchAssemblyFileInTempFolder(assemblyName);
if (!string.IsNullOrEmpty(foundPath))
{ {
var assemblyNameObj = new AssemblyName(args.Name); // 找到依赖项后,同样使用字节流加载!
var simpleName = assemblyNameObj.Name; // 这样保证主程序集和依赖程序集都在“无上下文”的环境中匹配
return LoadAddin(foundPath);
// 【关键修改 2】绝对不要在 AssemblyResolve 中手动处理 .resources
// 那个 "长度不能小于0" 的错误就是因为这里返回了错误的东西或者试图去加载主程序集
// 如果请求的是 .resources直接返回 null让 CLR 自己去临时目录的子文件夹里找
if (simpleName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase) ||
args.Name.Contains(".resources"))
{
return null;
}
// 1. 先在临时目录找
var text = SearchAssemblyFileInTempFolder(simpleName);
if (File.Exists(text))
{
return LoadAddin(text);
}
// 2. 临时目录没有,去源目录找
text = SearchAssemblyFileInOriginalFolders(simpleName);
// 3. 如果源目录找到了,复制到临时目录并加载
if (!string.IsNullOrEmpty(text))
{
assembly = CopyAndLoadAddin(text, true);
return assembly;
}
// 4. 如果还没找到,处理一些特殊情况(比如 XMLSerializers
// 这里的逻辑可以保留,但通常用处不大
if (simpleName.EndsWith(".XmlSerializers", StringComparison.OrdinalIgnoreCase))
{
// 忽略序列化程序集请求
return null;
}
// 5. 【可选】最后尝试手动弹窗选择(原代码逻辑),
// 但通常对于依赖项来说弹窗很烦人建议只针对主程序集弹窗或者直接返回null
// 如果这是为了解决找不到依赖的问题,上面 LoadFrom 改好后这里应该很少进来了
// 只有当你确实需要弹窗时保留下面代码
/*
var assemblySelector = new Wpf.AssemblySelectorWindow(args.Name);
if (assemblySelector.ShowDialog() == true)
{
text = assemblySelector.ResultPath;
assembly = CopyAndLoadAddin(text, true);
}
*/
} }
return assembly;
// 2. 如果临时文件夹没有,去源文件夹找 (并复制过来)
foundPath = SearchAssemblyFileInOriginalFolders(assemblyName);
if (!string.IsNullOrEmpty(foundPath))
{
return CopyAndLoadAddin(foundPath, true);
}
return null;
} }
private string SearchAssemblyFileInTempFolder(string simpleName) private string SearchAssemblyFileInTempFolder(string simpleName)
@@ -215,43 +172,35 @@ namespace AddInManager
string path = Path.Combine(TempFolder, simpleName + ext); string path = Path.Combine(TempFolder, simpleName + ext);
if (File.Exists(path)) return path; if (File.Exists(path)) return path;
} }
return string.Empty; return null;
} }
private string SearchAssemblyFileInOriginalFolders(string simpleName) private string SearchAssemblyFileInOriginalFolders(string simpleName)
{ {
var extensions = new string[] { ".dll", ".exe" }; var extensions = new string[] { ".dll", ".exe" };
// 1. 在 .NET 框架目录 (通常不需要System会自动加载,但保留也没事) // 1. 系统目录 (通常不需要System dll 会自动解析,但保留以防万一)
/*
foreach (var ext in extensions) foreach (var ext in extensions)
{ {
string path = Path.Combine(m_dotnetDir, simpleName + ext); string path = Path.Combine(m_dotnetDir, simpleName + ext);
if (File.Exists(path)) return path; if (File.Exists(path)) return path;
} }
*/
// 2. 所有引用过的源目录中找 // 2. 所有引用过的源文件夹
foreach (var ext in extensions) foreach (var ext in extensions)
{ {
foreach (var folder in m_refedFolders) foreach (var folder in m_refedFolders)
{ {
string path = Path.Combine(folder, simpleName + ext); string path = Path.Combine(folder, simpleName + ext);
if (File.Exists(path)) if (File.Exists(path)) return path;
{
return path;
}
} }
} }
// 3. 原代码中关于 Regression 的逻辑(看起来是特定环境的,如果不需要建议删除)
return null; return null;
} }
private bool IsAPIReferenced(Assembly assembly) private bool IsAPIReferenced(Assembly assembly)
{ {
// 保持原逻辑不变
if (string.IsNullOrEmpty(m_revitAPIAssemblyFullName)) if (string.IsNullOrEmpty(m_revitAPIAssemblyFullName))
{ {
foreach (var assembly2 in AppDomain.CurrentDomain.GetAssemblies()) foreach (var assembly2 in AppDomain.CurrentDomain.GetAssemblies())
@@ -263,7 +212,7 @@ namespace AddInManager
} }
} }
} }
// 防止未加载 RevitAPI 时崩溃 // 如果还没加载 RevitAPI (极其罕见),通过
if (string.IsNullOrEmpty(m_revitAPIAssemblyFullName)) return true; if (string.IsNullOrEmpty(m_revitAPIAssemblyFullName)) return true;
foreach (var assemblyName in assembly.GetReferencedAssemblies()) foreach (var assemblyName in assembly.GetReferencedAssemblies())

View File

@@ -8,14 +8,14 @@ using System.Runtime.Serialization;
namespace AddInManager namespace AddInManager
{ {
public class IniFile public class InitFile
{ {
public string FilePath { get; } public string FilePath { get; }
private readonly bool m_isJson; private readonly bool m_isJson;
private Dictionary<string, Dictionary<string, string>> m_jsonData; private Dictionary<string, Dictionary<string, string>> m_jsonData;
public IniFile(string filePath) public InitFile(string filePath)
{ {
FilePath = filePath; FilePath = filePath;
m_isJson = string.Equals(Path.GetExtension(FilePath), ".json", StringComparison.OrdinalIgnoreCase); m_isJson = string.Equals(Path.GetExtension(FilePath), ".json", StringComparison.OrdinalIgnoreCase);

View File

@@ -70,11 +70,7 @@
Click="SelectAllButton_Click" Click="SelectAllButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="选中所有命令"> ToolTip="选中所有命令">
<TextBlock <Path Data="{StaticResource Geo.SelectAll}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE73E;" />
</Button> </Button>
<Button <Button
@@ -82,11 +78,7 @@
Click="SelectNoneButton_Click" Click="SelectNoneButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="取消选中应用"> ToolTip="取消选中应用">
<TextBlock <Path Data="{StaticResource Geo.DeselectAll}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE739;" />
</Button> </Button>
</UniformGrid> </UniformGrid>
<Rectangle <Rectangle
@@ -101,11 +93,7 @@
Click="ExpandAllButton_Click" Click="ExpandAllButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="展开所有节点"> ToolTip="展开所有节点">
<TextBlock <Path Data="{StaticResource Geo.Expand}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE972;" />
</Button> </Button>
<Button <Button
@@ -113,11 +101,7 @@
Click="CollapseAllButton_Click" Click="CollapseAllButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="折叠所有节点"> ToolTip="折叠所有节点">
<TextBlock <Path Data="{StaticResource Geo.Collapse}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE971;" />
</Button> </Button>
</UniformGrid> </UniformGrid>
</StackPanel> </StackPanel>
@@ -140,12 +124,7 @@
Click="ContextMenuRun_Click" Click="ContextMenuRun_Click"
Header="运行"> Header="运行">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.Run}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE768;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
@@ -154,14 +133,9 @@
<MenuItem <MenuItem
x:Name="ContextMenuLoad" x:Name="ContextMenuLoad"
Click="ContextMenuLoad_Click" Click="ContextMenuLoad_Click"
Header="加载新插件..."> Header="加载...">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.LoadAssembly}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE8E5;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
@@ -169,12 +143,7 @@
Click="ContextMenuRemove_Click" Click="ContextMenuRemove_Click"
Header="移除"> Header="移除">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.Remove}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE74D;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
@@ -182,12 +151,7 @@
Click="ContextMenuReload_Click" Click="ContextMenuReload_Click"
Header="重新加载"> Header="重新加载">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.Reload}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE895;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
@@ -198,12 +162,7 @@
Click="ContextMenuOpenInExplorer_Click" Click="ContextMenuOpenInExplorer_Click"
Header="在资源管理器中显示"> Header="在资源管理器中显示">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.Explorer}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE8B7;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
@@ -211,12 +170,7 @@
Click="ContextMenuAssemblyInfo_Click" Click="ContextMenuAssemblyInfo_Click"
Header="查看程序集信息"> Header="查看程序集信息">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.Info}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE946;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
</ContextMenu> </ContextMenu>
@@ -238,11 +192,7 @@
Click="AppSelectAllButton_Click" Click="AppSelectAllButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="选中所有应用"> ToolTip="选中所有应用">
<TextBlock <Path Data="{StaticResource Geo.SelectAll}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE73E;" />
</Button> </Button>
<Button <Button
@@ -250,11 +200,7 @@
Click="AppSelectNoneButton_Click" Click="AppSelectNoneButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="取消选中应用"> ToolTip="取消选中应用">
<TextBlock <Path Data="{StaticResource Geo.DeselectAll}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE739;" />
</Button> </Button>
</UniformGrid> </UniformGrid>
<Rectangle <Rectangle
@@ -270,11 +216,7 @@
Click="AppExpandAllButton_Click" Click="AppExpandAllButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="展开所有应用程序节点"> ToolTip="展开所有应用程序节点">
<TextBlock <Path Data="{StaticResource Geo.Expand}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE972;" />
</Button> </Button>
<Button <Button
@@ -282,11 +224,7 @@
Click="AppCollapseAllButton_Click" Click="AppCollapseAllButton_Click"
Style="{StaticResource ToolbarButton}" Style="{StaticResource ToolbarButton}"
ToolTip="折叠所有应用程序节点"> ToolTip="折叠所有应用程序节点">
<TextBlock <Path Data="{StaticResource Geo.Collapse}" />
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Segoe MDL2 Assets"
Text="&#xE971;" />
</Button> </Button>
</UniformGrid> </UniformGrid>
</StackPanel> </StackPanel>
@@ -348,9 +286,10 @@
Margin="5" Margin="5"
Click="RunButton_Click" Click="RunButton_Click"
Style="{StaticResource ActionButton}" Style="{StaticResource ActionButton}"
Tag="Primary"> Tag="Primary"
ToolTip="运行选中的外部命令或应用程序">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE768;" /> <Path Data="{StaticResource Geo.Run}" />
<TextBlock Margin="5,0,0,0" Text="运行" /> <TextBlock Margin="5,0,0,0" Text="运行" />
</StackPanel> </StackPanel>
</Button> </Button>
@@ -359,9 +298,10 @@
Margin="5" Margin="5"
Click="LoadButton_Click" Click="LoadButton_Click"
Style="{StaticResource ActionButton}" Style="{StaticResource ActionButton}"
Tag="Primary"> Tag="Primary"
ToolTip="加载程序集">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE8E5;" /> <Path Data="{StaticResource Geo.LoadAssembly}" />
<TextBlock Margin="5,0,0,0" Text="加载" /> <TextBlock Margin="5,0,0,0" Text="加载" />
</StackPanel> </StackPanel>
</Button> </Button>
@@ -371,38 +311,35 @@
Click="RemoveButton_Click" Click="RemoveButton_Click"
LostFocus="RemoveButton_LostFocus" LostFocus="RemoveButton_LostFocus"
Style="{StaticResource ActionButton}" Style="{StaticResource ActionButton}"
Tag="Danger"> Tag="Danger"
ToolTip="移除选中的外部命令或应用程序">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Path Data="{StaticResource Geo.Remove}" />
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE74D;" />
<TextBlock Margin="5,0,0,0" Text="移除" /> <TextBlock Margin="5,0,0,0" Text="移除" />
</StackPanel> </StackPanel>
</Button> </Button>
<Button <Button
x:Name="saveSplitButton" x:Name="saveSplitButton"
Margin="5" Margin="5"
Click="SaveSplitButton_Click"> Click="SaveSplitButton_Click"
Style="{StaticResource ActionButton}"
Tag="Primary"
ToolTip="保存addin文件">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xEA35;" /> <Path Data="{StaticResource Geo.Save}" />
<TextBlock Margin="5,0,0,0" Text="保存" /> <TextBlock Margin="5,0,0,0" Text="保存" />
</StackPanel> </StackPanel>
<Button.ContextMenu> <Button.ContextMenu>
<ContextMenu x:Name="saveContextMenu"> <ContextMenu x:Name="saveContextMenu">
<MenuItem Click="SaveToAddinMenuItem_Click" Header="保存选中项到 Addins 文件夹"> <MenuItem Click="SaveToAddinMenuItem_Click" Header="保存选中项到 Addins 文件夹">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.SaveToDirectory}" />
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE78C;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<Separator /> <Separator />
<MenuItem Click="SaveLocalMenuItem_Click" Header="保存选中项到本地 .addin 文件"> <MenuItem Click="SaveLocalMenuItem_Click" Header="保存选中项到本地 .addin 文件">
<MenuItem.Icon> <MenuItem.Icon>
<TextBlock <Path Data="{StaticResource Geo.SaveToFile}" />
FontFamily="Segoe MDL2 Assets"
FontSize="14"
Text="&#xE792;" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
</ContextMenu> </ContextMenu>

View File

@@ -21,10 +21,64 @@
<SolidColorBrush x:Key="SecondaryTextBrush" Color="#605E5C" /> <SolidColorBrush x:Key="SecondaryTextBrush" Color="#605E5C" />
<SolidColorBrush x:Key="DisabledBrush" Color="#CCCCCC" /> <SolidColorBrush x:Key="DisabledBrush" Color="#CCCCCC" />
<SolidColorBrush x:Key="DisabledTextBrush" Color="#888888" /> <SolidColorBrush x:Key="DisabledTextBrush" Color="#888888" />
<!-- 全选 -->
<StreamGeometry x:Key="Geo.SelectAll">M1,1 H10 V10 H1 Z M5,5 H14 V14 H5 Z</StreamGeometry>
<!-- 取消全选 -->
<StreamGeometry x:Key="Geo.DeselectAll">M2,2 H14 V14 H2 Z M5,5 L11,11 M11,5 L5,11</StreamGeometry>
<!-- 折叠 (收起 - 减号/方框风格) -->
<StreamGeometry x:Key="Geo.Collapse">M2,2 H14 V14 H2 Z M5,8 H11</StreamGeometry>
<!-- 展开 (拉开 - 加号/方框风格) -->
<StreamGeometry x:Key="Geo.Expand">M2,2 H14 V14 H2 Z M5,8 H11 M8,5 V11</StreamGeometry>
<!-- 搜索 -->
<StreamGeometry x:Key="Geo.Search">M11,11 L15,15 M7,12 A5,5 0 1,1 7,2 A5,5 0 0,1 7,12</StreamGeometry>
<!-- 运行 -->
<StreamGeometry x:Key="Geo.Run">M5,3 L13,8 L5,13 Z</StreamGeometry>
<!-- 加载 -->
<StreamGeometry x:Key="Geo.LoadAssembly">M2,4 H8 V10 H2 Z M5,2 H11 V8 H5 Z M10,10 L15,10 M13,8 L15,10 L13,12</StreamGeometry>
<!-- 重新加载 -->
<StreamGeometry x:Key="Geo.Reload">M13,8 A5,5 0 1,1 10.5,3.5 M10.5,1 V3.5 H13</StreamGeometry>
<!-- 移除 -->
<StreamGeometry x:Key="Geo.Remove">M2,3 H14 M5,3 V14 H11 V3 M7,6 V11 M9,6 V11 M6,1 H10 V3 H6 Z</StreamGeometry>
<!-- 保存 -->
<StreamGeometry x:Key="Geo.Save">M3,2 H11 L14,5 V14 H3 Z M5,2 V6 H10 V2 M5,14 V10 H11 V14</StreamGeometry>
<!-- 保存到本地目录 (文件夹 + 向下箭头/盘片) -->
<StreamGeometry x:Key="Geo.SaveToDirectory">M1,3 H6 L8,5 H15 V13 H1 Z M11,7 V10 M9,8 L11,10 L13,8</StreamGeometry>
<!-- 保存到文件 (文档 + 磁盘) -->
<StreamGeometry x:Key="Geo.SaveToFile">M3,1 H10 L13,4 V15 H3 Z M5,12 H11 M5,9 H11 M9,1 V4 H12</StreamGeometry>
<!-- 查看信息 (i) -->
<StreamGeometry x:Key="Geo.Info">M8,1 A7,7 0 1,1 8,15 A7,7 0 0,1 8,1 M8,7 V11 M8,4 V4.5</StreamGeometry>
<!-- Windows资源管理器 (文件夹) -->
<StreamGeometry x:Key="Geo.Explorer">M1,3 H6 L8,5 H15 V13 H1 Z</StreamGeometry>
<!-- 定义一个通用 Path 样式,省得每次写重复属性 -->
<Style TargetType="Path">
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="Stroke" Value="{Binding RelativeSource={RelativeSource AncestorType=Control}, Path=Foreground}" />
<Setter Property="StrokeThickness" Value="1.5" />
<Setter Property="StrokeLineJoin" Value="Round" />
<Setter Property="StrokeStartLineCap" Value="Round" />
<Setter Property="StrokeEndLineCap" Value="Round" />
<Setter Property="Width" Value="16" />
<Setter Property="Height" Value="16" />
</Style>
<Style TargetType="TextBlock"> <Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontSize" Value="14" />
</Style> </Style>
<Style TargetType="Button"> <Style TargetType="Button">
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="12" />
@@ -51,6 +105,7 @@
<Trigger Property="IsEnabled" Value="False"> <Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource DisabledBrush}" /> <Setter Property="Background" Value="{StaticResource DisabledBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledTextBrush}" /> <Setter Property="Foreground" Value="{StaticResource DisabledTextBrush}" />
<Setter Property="BorderThickness" Value="0" />
</Trigger> </Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
@@ -81,15 +136,13 @@
<!-- 当 Tag="Primary" 时,应用主要按钮颜色 --> <!-- 当 Tag="Primary" 时,应用主要按钮颜色 -->
<DataTrigger Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Primary"> <DataTrigger Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Primary">
<Setter Property="Background" Value="{StaticResource PrimaryBrush}" /> <Setter Property="Foreground" Value="{StaticResource PrimaryBrush}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderBrush" Value="{StaticResource PrimaryBrush}" /> <Setter Property="BorderBrush" Value="{StaticResource PrimaryBrush}" />
</DataTrigger> </DataTrigger>
<!-- 当 Tag="Danger" 时,应用危险按钮颜色 --> <!-- 当 Tag="Danger" 时,应用危险按钮颜色 -->
<DataTrigger Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Danger"> <DataTrigger Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Danger">
<Setter Property="Background" Value="{StaticResource DangerBrush}" /> <Setter Property="Foreground" Value="{StaticResource DangerBrush}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderBrush" Value="{StaticResource DangerBrush}" /> <Setter Property="BorderBrush" Value="{StaticResource DangerBrush}" />
</DataTrigger> </DataTrigger>
@@ -103,7 +156,7 @@
<Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Primary" /> <Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Primary" />
<Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True" /> <Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True" />
</MultiDataTrigger.Conditions> </MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{StaticResource PrimaryHoverBrush}" /> <Setter Property="Foreground" Value="{StaticResource PrimaryHoverBrush}" />
</MultiDataTrigger> </MultiDataTrigger>
<!-- 当 Tag="Primary" 并且 IsPressed="True" --> <!-- 当 Tag="Primary" 并且 IsPressed="True" -->
@@ -112,7 +165,7 @@
<Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Primary" /> <Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Primary" />
<Condition Binding="{Binding Path=IsPressed, RelativeSource={RelativeSource Self}}" Value="True" /> <Condition Binding="{Binding Path=IsPressed, RelativeSource={RelativeSource Self}}" Value="True" />
</MultiDataTrigger.Conditions> </MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{StaticResource PrimaryPressedBrush}" /> <Setter Property="Foreground" Value="{StaticResource PrimaryPressedBrush}" />
</MultiDataTrigger> </MultiDataTrigger>
<!-- 当 Tag="Danger" 并且 IsMouseOver="True" --> <!-- 当 Tag="Danger" 并且 IsMouseOver="True" -->
@@ -121,7 +174,7 @@
<Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Danger" /> <Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Danger" />
<Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True" /> <Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True" />
</MultiDataTrigger.Conditions> </MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{StaticResource DangerHoverBrush}" /> <Setter Property="Foreground" Value="{StaticResource DangerHoverBrush}" />
</MultiDataTrigger> </MultiDataTrigger>
<!-- 当 Tag="Danger" 并且 IsPressed="True" --> <!-- 当 Tag="Danger" 并且 IsPressed="True" -->
@@ -130,8 +183,13 @@
<Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Danger" /> <Condition Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Danger" />
<Condition Binding="{Binding Path=IsPressed, RelativeSource={RelativeSource Self}}" Value="True" /> <Condition Binding="{Binding Path=IsPressed, RelativeSource={RelativeSource Self}}" Value="True" />
</MultiDataTrigger.Conditions> </MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{StaticResource DangerPressedBrush}" /> <Setter Property="Foreground" Value="{StaticResource DangerPressedBrush}" />
</MultiDataTrigger> </MultiDataTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource DisabledBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledTextBrush}" />
<Setter Property="BorderThickness" Value="0" />
</Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<!-- 浏览按钮样式 --> <!-- 浏览按钮样式 -->
@@ -265,16 +323,10 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<!-- 搜索图标 --> <!-- 搜索图标 -->
<TextBlock <Path
Margin="8,0,0,0" Margin="4,4,0,0"
HorizontalAlignment="Left" Data="{StaticResource Geo.Search}"
VerticalAlignment="Center" Stroke="{StaticResource SecondaryTextBrush}" />
FontFamily="Segoe MDL2 Assets"
FontSize="12"
Foreground="{StaticResource SecondaryTextBrush}"
IsHitTestVisible="False"
Text="&#xE721;" />
<!-- 这是TextBox实际输入内容的地方 --> <!-- 这是TextBox实际输入内容的地方 -->
<ScrollViewer <ScrollViewer
x:Name="PART_ContentHost" x:Name="PART_ContentHost"
@@ -288,6 +340,7 @@
x:Name="Watermark" x:Name="Watermark"
Grid.Column="1" Grid.Column="1"
Margin="{TemplateBinding Padding}" Margin="{TemplateBinding Padding}"
Padding="2,0,0,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="{StaticResource SecondaryTextBrush}" Foreground="{StaticResource SecondaryTextBrush}"
IsHitTestVisible="False" IsHitTestVisible="False"
@@ -672,9 +725,14 @@
<!-- 选中状态的勾选标记 --> <!-- 选中状态的勾选标记 -->
<Path <Path
x:Name="CheckMark" x:Name="CheckMark"
Width="12"
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 3,9 L 7,13 L 15,5" Data="M 3,9 L 7,13 L 15,5"
Fill="Transparent" Fill="Transparent"
Stroke="White" Stretch="Uniform"
Stroke="{StaticResource PrimaryBrush}"
StrokeLineJoin="Round" StrokeLineJoin="Round"
StrokeThickness="2" StrokeThickness="2"
Visibility="Collapsed" /> Visibility="Collapsed" />
@@ -686,7 +744,7 @@
Height="2" Height="2"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Fill="White" Fill="{StaticResource PrimaryBrush}"
Visibility="Collapsed" /> Visibility="Collapsed" />
</Grid> </Grid>
</Border> </Border>
@@ -700,14 +758,14 @@
<!-- 选中状态 --> <!-- 选中状态 -->
<Trigger Property="IsChecked" Value="True"> <Trigger Property="IsChecked" Value="True">
<Setter TargetName="CheckMark" Property="Visibility" Value="Visible" /> <Setter TargetName="CheckMark" Property="Visibility" Value="Visible" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryBrush}" /> <!--<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryBrush}" />-->
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryBrush}" />
</Trigger> </Trigger>
<!-- 不确定状态 --> <!-- 不确定状态 -->
<Trigger Property="IsChecked" Value="{x:Null}"> <Trigger Property="IsChecked" Value="{x:Null}">
<Setter TargetName="IndeterminateMark" Property="Visibility" Value="Visible" /> <Setter TargetName="IndeterminateMark" Property="Visibility" Value="Visible" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryBrush}" /> <!--<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryBrush}" />-->
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryBrush}" />
</Trigger> </Trigger>
@@ -730,7 +788,6 @@
<Condition Property="IsMouseOver" Value="True" /> <Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsChecked" Value="True" /> <Condition Property="IsChecked" Value="True" />
</MultiTrigger.Conditions> </MultiTrigger.Conditions>
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryHoverBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryHoverBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryHoverBrush}" />
</MultiTrigger> </MultiTrigger>
@@ -740,13 +797,11 @@
<Condition Property="IsMouseOver" Value="True" /> <Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsChecked" Value="{x:Null}" /> <Condition Property="IsChecked" Value="{x:Null}" />
</MultiTrigger.Conditions> </MultiTrigger.Conditions>
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryHoverBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryHoverBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryHoverBrush}" />
</MultiTrigger> </MultiTrigger>
<!-- 按下状态 --> <!-- 按下状态 -->
<Trigger Property="IsPressed" Value="True"> <Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryPressedBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryPressedBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryPressedBrush}" />
</Trigger> </Trigger>
</ControlTemplate.Triggers> </ControlTemplate.Triggers>

View File

@@ -4,7 +4,7 @@
; 定义应用程序的名称 ; 定义应用程序的名称
#define MyAppName "RevitAddinManager" #define MyAppName "RevitAddinManager"
; 定义应用程序的版本号 ; 定义应用程序的版本号
#define MyAppVersion "1.0.0.0" #define MyAppVersion "3.2.0"
; 定义应用程序的发布者 ; 定义应用程序的发布者
#define MyAppPublisher "ShrlAlgo" #define MyAppPublisher "ShrlAlgo"
; 定义应用程序的网址 ; 定义应用程序的网址