簡體   English   中英

如何在 WPF 設計器、.NET 6.0 中獲取應用程序目錄?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM