我的 WPF 应用程序从相对于主应用程序可执行文件的位置读取目录结构。
然后它将目录结构可视化为TreeView
.
当我只运行应用程序时它工作正常,但是,当我在 XAML 设计器中预览它时,它不起作用。我发现它是从这样的不同位置加载的:
C:\Users\Adam\AppData\Local\Microsoft\VisualStudio\17.0_108779a0\Designer\Cache\1481370356x64DA\
是的,这就是System.AppDomain.CurrentDomain.BaseDirectory
财产的价值。
我从assembly.Location
.
我知道很久以前有人问过类似的问题,答案对以前的 Visual Studio 版本和以前的 .NET 版本有效。它们都不适用于 .NET 6 和 Visual Studio 2022。请不要将其标记为这些问题的重复。
要验证这些答案不适用于 .NET 6 - 只需创建一个新的 .NET 6 WPF 项目,在视图执行的任何代码中插入以下代码:
throw new Exception($"Path: {System.AppDomain.CurrentDomain.BaseDirectory}");
重新加载设计器,你会明白我在说什么。
我已经找到了一个非常丑陋的解决方法,但它只是hhhhhhideous!当我故意抛出并捕获异常时。我将在堆栈跟踪中获得我的代码的路径。然后我可以从那里提取我的项目目录,然后在项目文件中找到输出路径,就是这样。但是来吧!必须有更清洁的方法!
更新: 这是hhhhhhideous hack:
using System.IO;
using System.Reflection;
using System.Xml;
static class Abominations {
/// <summary>
/// Gets the calling project's output directory in a hideous way (from debug information). Use when all else fails.
/// </summary>
/// <param name="action">Action that throws an exception.</param>
/// <returns>Calling project's output directory.</returns>
public static string GetCallingProjectOutputDirectory(Action action) {
try {
action();
}
catch (Exception exception) {
var stacktrace = exception.StackTrace!.Split(Environment.NewLine).First();
var p1 = stacktrace.IndexOf(" in ") + 4;
var p2 = stacktrace.IndexOf(":line");
var pathLength = p2 - p1;
if (p1 < 0 || p2 < 0 || pathLength < 1) throw new InvalidOperationException("No debug information");
var callingSource = stacktrace[p1..p2];
var directory = new DirectoryInfo(Path.GetDirectoryName(callingSource)!);
FileInfo? projectFile;
do {
projectFile = directory.GetFiles("*.csproj").FirstOrDefault();
if (projectFile is null) directory = directory.Parent!;
}
while (projectFile is null);
var projectXml = new XmlDocument();
projectXml.Load(projectFile.FullName);
var baseOutputPath = projectXml.GetElementsByTagName("BaseOutputPath").OfType<XmlElement>().FirstOrDefault()?.InnerText;
var outputDirectory = directory.FullName;
outputDirectory = baseOutputPath is not null
? Path.GetFullPath(Path.Combine(outputDirectory, baseOutputPath))
: Path.Combine(outputDirectory, "bin");
var buildConfiguration =
Assembly.GetCallingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>()!.Configuration;
var targetFramework =
projectXml.GetElementsByTagName("TargetFramework").OfType<XmlElement>().FirstOrDefault()!.InnerText;
outputDirectory = Path.Combine(outputDirectory, buildConfiguration, targetFramework);
return outputDirectory;
}
throw new InvalidOperationException("Provided action should throw");
}
}
我测试了它并且它有效。但这只是一个残暴的可憎之物,应该被火烧死。