How do I get the application's directory from

2019-04-10 10:12发布

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.

5条回答
贼婆χ
2楼-- · 2019-04-10 10:54

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?

查看更多
Juvenile、少年°
3楼-- · 2019-04-10 10:55

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.

查看更多
Explosion°爆炸
4楼-- · 2019-04-10 10:56

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("John@smith.com"); } }
}

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.

查看更多
女痞
5楼-- · 2019-04-10 11:06

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.

查看更多
ら.Afraid
6楼-- · 2019-04-10 11:08

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.

查看更多
登录 后发表回答