如何在设计时从 WPF 应用程序获取应用程序的目录?

发布于 2024-08-12 06:09:49 字数 549 浏览 4 评论 0原文

如何在设计时从 WPF 应用程序获取应用程序的目录? 我需要在设计时访问应用程序当前目录中的资源,同时我的 XAML 显示在设计器中。我无法使用此问题 在设计时,System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)System.Reflection.Assembly.GetExecutingAssembly().Location指向 IDE 的位置(Visual Studio...Common7 或其他)。

根据要求进一步明确我的目标:我想在设计时访问数据库表并显示该数据的图形。该设计是在 Visual Studio 2008 中完成的,因此我需要的是针对一个非常具体的问题的非常具体的解决方案,那就是获取我的应用程序的程序集目录。

How do I get the application's directory from my WPF application, at design time? I need to access a resource in my application's current directory at design time, while my XAML is being displayed in the designer. I'm not able to use the solution specified in this question as at design time both System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) and System.Reflection.Assembly.GetExecutingAssembly().Location point to the IDE's location (Visual Studio... Common7 or something).

Upon request to further clarify my goals: I want to access a database table at design time and display a graphic of that data. The design is done in Visual Studio 2008, so what I need is a very specific solution to a very specific problem, and that is getting the assembly directory for my app.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

流星番茄 2024-08-19 06:09:49

从您的描述来看,您的代码实际上是在 Visual Studio 内的 WPF 设计器内运行,例如,它是用于设计的自定义控件库的一部分。

在本例中,Assembly.GetEntryAssembly() 返回 null,但以下代码获取应用程序目录的路径:

  string applicationDirectory = (
    from assembly in AppDomain.CurrentDomain.GetAssemblies()
    where assembly.CodeBase.EndsWith(".exe")
    select System.IO.Path.GetDirectoryName(assembly.CodeBase.Replace("file:///", ""))
    ).FirstOrDefault();

可以使用以下步骤来演示在 VS.NET 2008 的 WPF Designer 工具中的工作原理:

  1. 将此代码放入“WPF 自定义控件库”或“类库”项目中
  2. 添加读取数据库并返回显示数据所需的任何代码(在我的例子中,我只是将应用程序目录本身作为字符串返回)
  3. 引用库您正在设计的项目中的项目
  4. 使用 XAML 文件中的自定义控件或类来填充 DataContext 或以其他方式向 UI 提供数据(在我的例子中,我使用 x:Static 绑定 DataContext) 使用
  5. “Windows Presentation Foundation”编辑该 XAML 文件Designer”,只需双击即可完成,除非您更改了默认编辑器,在这种情况下使用“打开方式...”

当您按照这些步骤操作时,您正在查看的对象将填充来自您的数据数据库在运行时和设计时都以相同的方式。

在其他场景中,相同的技术也能发挥同样的作用,并且根据您的需求,还有其他可用的解决方案。如果您的需求与我上面假设的不同,请告诉我们。例如,如果您正在编写 VS.NET 插件,那么您将面临完全不同的游戏。

From your description it sounds like your code is actually running inside the WPF Designer within Visual Studio, for example it is part of a custom control library that is being used for design.

In this case, Assembly.GetEntryAssembly() returns null, but the following code gets the path to the application directory:

  string applicationDirectory = (
    from assembly in AppDomain.CurrentDomain.GetAssemblies()
    where assembly.CodeBase.EndsWith(".exe")
    select System.IO.Path.GetDirectoryName(assembly.CodeBase.Replace("file:///", ""))
    ).FirstOrDefault();

The following steps can be used to demonstrate this works inside VS.NET 2008's WPF Designer tool:

  1. Place this code inside a "WPF Custom Control Library" or "Class Library" project
  2. Add whatever code is necessary to read the database and return the data for display (in my case I just returned the application directory itself as a string)
  3. Reference the library project from the project you are designing
  4. Use the custom controls or classes from a XAML file to populate your DataContext or otherwise supply data to your UI (in my case I bound DataContext using x:Static)
  5. Edit that XAML file with the "Windows Presentation Foundation Designer", which can be done by just double-clicking unless you have changed your default editor, in which case use "Open With..."

When you follow these steps, the object you are looking at will be populated with data from your database the same way both at run time and design time.

There are other scenarios in which this same technique works just as well, and there are other solutions available depending on your needs. Please let us know if your needs are different those I assumed above. For example, if you are writing a VS.NET add-in, you are in a completely different ball game.

↘紸啶 2024-08-19 06:09:49

您是否想支持设计师(例如视觉工作室设计师或 Blend)?

如果是这样,那么有多种不同的方法来解决这个问题。您通常不想依赖可执行文件的相对路径,因为它可以托管在各种不同的设计工具(VS、Expression Blend 等)中。

也许您可以更全面地解释您要解决的问题,以便我们可以提供更好的答案?

Are you trying to support a designer (such as the visual studio designer or Blend)?

If so then there are various different ways to approach this problem. You typically don't want to rely a relative path from executable because it can be hosted in various different design tools (VS, Expression Blend etc..)

Maybe you can more fully explain the problem you are trying to solve so we can provide a better answer?

薯片软お妹 2024-08-19 06:09:49

我认为这是不可能的 - 您正在询问可能尚未构建的程序集的位置。您的设计时代码不会在应用程序内部运行,并且必须对 IDE 做出一些假设。这对我来说是错误和脆弱的 - 考虑这些问题:

  • 该项目已经建成了吗?
  • 如果没有,则没有可执行文件可获取路径,那么怎么办?
  • 如果尚未构建,其他文件是否会存在,或者它们是否构建了工件?
  • 如果建了,建到哪里了?
  • 您需要考虑其他 IDE 吗?

在这种情况下,您可能应该在设计时要求用户通过在对象上添加属性供他们编辑来提供或浏览路径。然后,您的设计时代码可以使用该属性的值来查找它需要的内容。

I don't think this is possible - you're asking for the location of an assembly that potentially hasn't even been built yet. Your design-time code does not run inside your application and would have to make some assumptions about the IDE. This feels wrong and brittle to me - consider these questions:

  • Has the project been built yet?
  • If not, there is no executable to get the path of, so what then?
  • Would the other files be present if it hasn't been built, or are they build artefacts?
  • If it has been built, where was it built to?
  • Do you need to consider other IDEs?

In this situation you should probably ask the user, at design time, to provide or browse for a path by adding a property on your object for them to edit. Your design time code can then use the value of the property to find what it needs.

一腔孤↑勇 2024-08-19 06:09:49

如果您广泛使用装饰器等进行 WPF 设计器工作,请使用“Context”属性/类型

详细信息:-
在设计时,您有 modelItem 的实例(我假设它,您知道)如果没有,那么您可以在

DesignAdorner 类中的Activate 方法的 Override 实现 //

public class DesignAdorner : PrimarySelectionAdornerProvider
{
      protected override void Activate(ModelItem item)
        {
                modelItem = item;
        }
}

中实例化它现在您可以使用以下单行代码访问当前应用程序路径

string aplicationPathDir = System.IO.Directory.GetParent(modelItem.Context.ToString()).FullName;

让我知道,如果这对你没有帮助。

If you are extensively working on WPF designers using adorner etc, please use "Context" property/type

Details:-
In Design time you have instance of modelItem (I assume it, you know it) if not then you can instantiate it in Override implementation of Activate method

// in DesignAdorner class

public class DesignAdorner : PrimarySelectionAdornerProvider
{
      protected override void Activate(ModelItem item)
        {
                modelItem = item;
        }
}

Now you can access the current application path using following single line code

string aplicationPathDir = System.IO.Directory.GetParent(modelItem.Context.ToString()).FullName;

Let me know, if it does not help you.

黎夕旧梦 2024-08-19 06:09:49

好的,鉴于这里的进一步说明,这就是我要做的。

与 GraemeF 提出的担忧一致,做你想做的事情是脆弱的,充其量也容易崩溃。

因此,一般做法是将设计时数据支持视为与运行时数据支持完全不同的方法。很简单,您在设计时环境和该数据库之间创建的耦合是一个坏主意。

为了简单地提供用于可视化的设计时数据,我更喜欢使用遵循公共接口的模拟类作为运行时类。这为我提供了一种显示数据的方法,我可以确保这些数据具有正确的类型并且符合与运行时对象相同的约定。然而,这是一个完全不同的类,用于设计时支持(并且通常用于单元测试)。

例如。如果我有一个运行时类需要显示人员详细信息,例如名字、姓氏和电子邮件:

public class Person()
{
    public String FirstName { get; set;}
    public String LastName {get; set;}
    public Email EmailAddress {get; set;}
}

并且我在运行时从数据库填充此对象,但还需要提供设计时可视化,我将引入一个 IPerson 接口定义要遵守的契约,即强制属性 getter 存在:

public interface IPerson()
{
    String FirstName { get; }
    String LastName { get; }
    Email EmailAddress { get; }
}

然后我将更新运行时 Person 类以实现该接口:

public class Person() : IPerson
{
public String FirstName { get; set;}
public String LastName {get; set;}
public Email EmailAddress {get; set;}
}

然后我将创建一个模拟类,该类实现相同的接口并为设计时使用提供合理的值

public MockPerson() : IPerson
{
public String FirstName { get { return "John"; } }
public String LastName { get { return "Smith"; } } 
public Email EmailAddress { get { return new Email("[email protected]"); } }
}

然后我将实现一种机制,在设计时提供 MockPerson 对象,在运行时提供真实的 Person 对象。像 这个这个。这提供了设计时数据支持,而无需运行时和设计时环境之间的硬依赖。

这种模式更加灵活,允许您在整个应用程序中提供一致的设计时数据支持。

Ok given the further clarification here is what I would do.

staying in line with the concern raised by GraemeF, doing what you want is brittle and prone to breaking at best.

Because of this the general practice is to treat design time data support as a wholly different approach then runtime data support. Very simply, the coupling you are creating between your design time environment and this DB is a bad idea.

To simply provide design time data for visualization I prefer to use a mock class that adheres to a common Interface as the runtime class. This gives me a way to show data that I can ensure is of the right type and conforms to the same contract as my runtime object. Yet, this is a wholly different class that is used for design time support (and often used for Unit Testing).

So for example. If I had a run time class that needs to show person details such as first name, last name and Email:

public class Person()
{
    public String FirstName { get; set;}
    public String LastName {get; set;}
    public Email EmailAddress {get; set;}
}

and I was populating this object from a DB at runtime but also need to provide a design time visualization I would introduce an IPerson interface that defines the contract to adhere to, namely enforces that the property getters exist:

public interface IPerson()
{
    String FirstName { get; }
    String LastName { get; }
    Email EmailAddress { get; }
}

Then I would update my runtime Person class to implement the interface:

public class Person() : IPerson
{
public String FirstName { get; set;}
public String LastName {get; set;}
public Email EmailAddress {get; set;}
}

Then I would create a mock class that implements the same interface and provides sensible values for design time use

public MockPerson() : IPerson
{
public String FirstName { get { return "John"; } }
public String LastName { get { return "Smith"; } } 
public Email EmailAddress { get { return new Email("[email protected]"); } }
}

Then I would implement a mechanism to provide the MockPerson object at design time and the real Person object at runtime. Something like this or this. This provides design time data support without the hard dependency between the runtime and design time environments.

This pattern is much more flexible and will allow you to provide consistent design time data support throughout your application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文