[英]How to get the application directory in WPF designer, .NET 6.0?
我的 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 。 當我故意拋出並捕獲異常時。 我將在堆棧跟蹤中獲得我的代碼的路徑,然后我可以從那里提取我的項目目錄。 然后在工程文件中找到output路徑就可以了。 但是來吧! 必須有更清潔的方法!
更新:這是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");
}
}
我測試了它並且它有效。 但這只是一個殘暴的可憎之物,應該被火燒死。
假設您有這樣的 DataContext class :
public class ViewModel
{
public string Path { get; set; }
public ViewModel()
{
Path = AppDomain.CurrentDomain.BaseDirectory;
}
}
如果您對此 Datacontext 進行綁定,例如這樣:
<Grid>
<TextBlock Text="{Binding Path}"></TextBlock>
</Grid>
實際上,在設計器和運行時之間找到了不同的路徑。 以下是通常適用於此類問題的解決方案:
創建一個派生自 DataContext class 的 class,並設置一個測試值(僅對 Designer 上下文有效):
public class DesignViewModel : ViewModel
{
public DesignViewModel()
{
Path = "Path for Designer only";
}
}
然后,使用此 class 設置 Designer Datacontext:
d:DataContext="{d:DesignInstance Type=local:DesignViewModel, IsDesignTimeCreatable=True}"
這是一種通過強制為 Designer 設置您想要的值來解決問題的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.