views:

766

answers:

4

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.

A: 

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.

GraemeF
"assumptions about the IDE"? What assumptions? It's Visual Studio, and I want the path to my project's Release folder if the build conf is Release and to my Debug folder otherwise.
luvieere
I mean you will need to know where it will output the assemblies when built. Maybe you could tell us more about the reasons why you want to do this; perhaps there's a simpler solution to the problem?
GraemeF
No simpler solution: 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.
luvieere
I've added a bit more detail in light of the extra information, but it doesn't sound like the right approach to me so my answer is still essentially "don't." /shrug
GraemeF
Is the database table generic, or specific to this one project? IOW, is it a table in an instance of SQL Server that's available to other projects, or is it a local table using something other than a DBMS (eg., an XML database)? If it's generic, you can hard-code it; if it's project specific, I agree with Graeme that a property the user can edit to give you the path would be the best suggestion so far.
Ken White
I can move the project in another folder, so it's not viable to hardcode. The database is a Firebird database file, in the projects's Debug directory. Now how do I get the path to it?
luvieere
Would it make sense to include the database file as a Resource in the project? that would allow you to reference it in your xaml using pack://application type syntax
qntmfred
A: 

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?

Foovanadil
A: 

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.

Foovanadil
Why do I have to settle for a mock solution? I don't want to see that table populated with garbage at design time, I want that every time I cast an eye on it to be able to see the real data even before I recompile my project. I might happen to work on some other part of the project and actually need that data to make a decision there without having to recompile. It's much more convenient to just have it there, with all its associated transformations, displayed as I want it at design time, rather than gleaning it out of the database.
luvieere
+2  A: 

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.

Ray Burns