#1,212 – Viewing WPF Trace Output Outside of Visual Studio

When you’re running a WPF application from within Visual Studio, you can view trace output in Visual Studio’s Output window. That is, you’ll see any trace output that you generate using Trace.WriteLine. This doesn’t work, however, if you’re not running in Debug mode or when you run your application outside of Visual Studio.

There’s a tool that you can use, however, to capture Trace output for a WPF application, even if it it’s a Release build and is running outside of Visual Studio.

The DebugView tool, available for download here, will display debug output for all applications in Windows. This includes .NET Trace output, which means that the application will display all trace output while your application is running.

Note that DebugView shows debug output for all applications, which means that you may need to filter out applications that you don’t care about. (See OutputDebugString call in the Win32 library).

Let’s say that we do the following in a Button_Click event:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Trace.WriteLine($"You clicked a button at {DateTime.Now.ToLongTimeString()}");
        }

We can now build and run the WPF application (i.e. after shutting down Visual Studio). Running DebugView, you can see the output.

#1,111 – Referencing Content Files from XAML

You can choose whether to embed an image resource in your application’s executable file or to have the file copied to the output directory.

Whether the image resource is embedded in the executable or copied to the output directory, you can reference the image from XAML elements in the same way, by just using the name of the image (assuming that the image is located in the root of the solution).

Below, the “Chico” image has its Build Action set to Resource (embed in executable).  The “Groucho” image has its Build Action set to Content (read from output directory).

1111-001   1111-002

In XAML, we refer to the images in the same way.

    <StackPanel Orientation="Horizontal">
        <Image Source="Groucho.jpg" Height="100"
               Margin="10"/>
        <Image Source="Chico.jpg" Height="100"
               Margin="10"/>
    </StackPanel>

When we run the application, both images are loaded successfully.

1111-003

#1,110 – Using a Resource as a Content File

When your application needs to use a resource (e.g. an image), it can embed the resource in the executable for the application.  You can then access the resource at run time using a Uri like the one shown below.

BitmapImage bmi = new BitmapImage(new Uri("pack://application:,,,/Ted.jpg"));

You can also include an image in your project and then cause the image to be placed in an output directory along with the executable, but not embedded within it.  You do this by setting its Build Action to Content and by setting the Copy to Output Directory property.

1110-001

In this case, after building the project, the .jpg file is copied to the output directory.

1110-002

At run time, you can use exactly the same Uri to access the file, although it is external to the application, rather than embedded.

#1,109 – Accessing a Resource in a Different Assembly

You can use the following URI, in code, to access a resource embedded into the executing assembly.

                    BitmapImage bmi = new BitmapImage(new Uri("pack://application:,,,/Images/Ted.jpg"));

If you want to access a resource in a different assembly, you use the Uri syntax shown below, adding the assembly name and the word “component”.

                    BitmapImage bmi = new BitmapImage(new Uri("pack://application:,,,/MyPictures;component/Ted.jpg"));

This assumes that the image Ted.jpg is included in an assembly named MyPictures (e.g. in MyPictures.dll).  It also assumes that the Build Action for the image is set to Resource and that this assembly is in the same directory as the executing assembly.  If you want the resource assembly to end up in the same output directory as the main assembly, you’ll want to add a reference to it from the main assembly.

#1,108 – Use Reflector to Get List of Resources

You can use the third party .NET Reflector tool to get more information on the contents of a .NET (e.g. WPF) assembly.  .NET Reflector is available from Red Gate Software.  Included in the list of information displayed in Reflector is a full list of all resources embedded in the assembly.

To start with, you open the assembly within Reflector.  You do this by browsing to the .exe file containing the assembly.

1108-001

 

Once you open the assembly, you can look at the contents, including any resources embedded within the assembly.  In the example below, we find the image ted.jpg in the images sub-folder.

1108-002

 

 

 

#1,107 – Accessing an Embedded Resource Using a Uri

You can embed images into your WPF application as resources and then access them from code at run-time.

To embed an image as a resource, add it to your project and set its Build Action to Resource.

1107-001

You can now access this image at run-time using a Uri.  The URI for a simple resource just includes the path to the image.

In the example below, we use a URI to locate an image in the Images folder.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                BitmapImage bmi = new BitmapImage(new Uri("pack://application:,,,/Images/Ted.jpg"));

                MessageBox.Show(string.Format("Image is {0}x{1} pixels", bmi.Width, bmi.Height));
            }
            catch (Exception xx)
            {
                MessageBox.Show(xx.ToString());
            }
        }

The pack://application portion of the Uri indicates that the resource is compiled into the current assembly.  The portion of the Uri after the third comma describes the path to the image.

1107-002

#1,106 – Creating a Single Instance Application

By default, when you build an application, the user can run multiple copies of the application.  Each one runs independently, managing its own window(s).  There are times, however, when you might want to enforce that no more than one instance of your application runs at a time.  You can do this using the Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase class.

You start by adding a reference to Microsoft.VisualBasic.dll.

1106-01

1106-02

You next create a class that derives from WindowsFormsApplicationBase and does the following:

  • Sets IsSingleInstance property to true (in constructor)
  • Overrides OnStartup method and creates an instance of your main WPF application class
    • (For first startup)
  • Overrides OnStartupNextInstance and reactivates the main window
    • (For subsequent startups)
    public class MyApplicationBase : WindowsFormsApplicationBase
    {
        private App myApp;

        public MyApplicationBase()
        {
            this.IsSingleInstance = true;
        }

        // Called when user starts the first instance of the app
        protected override bool OnStartup(StartupEventArgs eventArgs)
        {
            myApp = new App();
            myApp.InitializeComponent();

            // Run application (this call blocks)
            myApp.Run();

            return false;
        }

        // Called when user tries starting another instance
        protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
        {
            base.OnStartupNextInstance(eventArgs);

            // App already running, so just bring window to front
            if (myApp.MainWindow.WindowState == System.Windows.WindowState.Minimized)
                myApp.MainWindow.WindowState = System.Windows.WindowState.Normal;
            myApp.MainWindow.Activate();
        }
    }

Next, you need to create a new Main method, where you’ll instantiate the new class.

    public class Startup
    {
        [STAThread]
        public static void Main(string[] args)
        {
            MyApplicationBase appBase = new MyApplicationBase();
            appBase.Run(args);
        }
    }

Finally, you’ll configure the project properties so that this new Startup.Main method is the startup object for your application.
1106-03