WPF progress window in separate thread

Many times I faced with the situations where my program load huge amount of data. Obviously, the best way is to use BackgroundWorker class to separate main application thread and data loading.

But sometimes it’s necessary to perform some operations in main thread. In this situation we have to inform user that our applicaton perform some operation and it can take some time. Simply, it’s possible to show progress window and information string. But if we show progress window in the same thread that the main program, our progress window will be busy.

The solution of this proglem is to show progress window in the separate thread.

1. Let’s create new WPF Applocation project in VS.

2. Right click on the project and choose “Add” -> “New item”. Select “Windows (WPF)” element, set name “ProgressWindow” and click “Add” button.

3. Drop progress bar control on the ProgressWindow form.

<Window x:Class="WPFProgressWindow.ProgressWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ProgressWindow" Width="300" SizeToContent="Height" >

    <StackPanel Margin="10">
        <ProgressBar Name="Progress" Width="200" Height="20" Minimum="0" Maximum="1" Margin="10" Orientation="Horizontal" />
        <TextBlock HorizontalAlignment="Center" Name="StatusText" Margin="10" Height="50" Foreground="Black" Text="Loading..."/>
    </StackPanel>
</Window>

You can use your own progress instead of standard control. Follow by this link to find out how create custom progress in WPF and Silverlight.
3. Go to code in ProgressWindow and create new class:

public class ProgressManager
{
   private Thread thread;
   private bool canAbortThread = false;
   private ProgressWindow window;

   public void BeginWaiting()
   {
       this.thread = new Thread(this.RunThread);
       this.thread.IsBackground = true;
       this.thread.SetApartmentState(ApartmentState.STA);
       this.thread.Start();
   }
   public void EndWaiting()
   {
       if (this.window != null)
       {
           this.window.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
           { this.window.Close(); }));
           while (!this.canAbortThread) { };
       }
       this.thread.Abort();
   }

   public void RunThread()
   {
       this.window = new ProgressWindow();
       this.window.Closed += new EventHandler(waitingWindow_Closed);
       this.window.ShowDialog();
   }
   public void ChangeStatus(string text)
   {
       if (this.window != null)
       {
            this.window.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
            { this.window.tbStatus.Text = text; }));
       }
   }
   public void ChangeProgress(double Value)
   {
       if (this.window != null)
       {
           this.window.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
           { this.window.pProgress.Value = Value; }));
       }
   }
   public void SetProgressMaxValue(double MaxValue)
   {
       Thread.Sleep(100);
       if (this.window != null)
       {
           this.window.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
           {
                this.window.pProgress.Minimum = 0;
                this.window.pProgress.Maximum = MaxValue;
           }));
       }
   }
   void waitingWindow_Closed(object sender, EventArgs e)
   {
       Dispatcher.CurrentDispatcher.InvokeShutdown();
       this.canAbortThread = true;
   }
}

BeginWaiting method only create new thread and run RunThread() method inside. EndWaiting method try to close opened progress window and stop thread. Using SetProgressMaxValue method we can set minimum and maximun values of progress. Both ChangeStatus and ChangeProgress methods is used for changing progress value and information string text.
I call Thread.Sleep(100) in SetProgressMaxValue because window is created in separate thread so, if we call SetProgressMaxValue after BeginWaiting method possibly window has not been created at this time.

4. Finally, drop button in the main window and add click event hander for it.

private void button1_Click(object sender, RoutedEventArgs e)
{
      ProgressManager pm = new ProgressManager();
      pm.BeginWaiting();
      pm.SetProgressMaxValue(10);

      for (int i = 0; i < 10; i++)
      {
             pm.ChangeStatus("Loading " + i.ToString() + " from 10");
             pm.ChangeProgress(i);
             Thread.Sleep(1000);
      }

      pm.EndWaiting();
}

Well, now our progress window work fine in separate thread.

Using unmanaged Dll libraries and setting default dll directory for .NET application

Sometimes it’s necessary to call Windows API functions or some custom functions from DLL libraries (not assemblies) in .Net applications (C# or VB.net). For example, we have DLL library created in Visual C++ or Delphi. So, how can we call functions in this library?First of all we need add references on this libraries to our project? Using menu “Add references” is not good idea because it works only with .net assemblies. If you try to add reference on this dll library you’ve got next error message:

To solve this problem you shoud use DllImport attribute in your project. Let’s try to call MessageBox API function from user32.dll library by using DllImport attribute.
I will show this example by using C# console application.
To solve this problem you shoud use DllImport attribute in your project. Let’s try to call MessageBox API function from user32.dll library by using DllImport attribute.
I will show this example by using C# console application.
using System;
using System.Runtime.InteropServices;

namespace test
{
    class Program
    {
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int MessageBox(System.IntPtr hWnd, String lpText, String lpCaption, System.UInt32 uType);

        static void Main(string[] args)
        {
            MessageBox(System.IntPtr.Zero, "Test", "Text", 0);
        }
    }
}
After attribute DllImport I declare WinAPI function MessageBox. Prototype of this function you can find in MSDN. It’s important to mark all unmanaged dll function with keywords static and extern.
Run this project and you will see standard windows dialog message box.
Now let’s consider next situation: for example you have your own dll library and you want to distribute this library with application.
So, there is two ways: you should add this library into root of project or add special folder to project and add file there.
Don’t forget to mark library as content:

Well, now if you bild your project dll library will copy to output directory. But there is some problem. If you library located in subfolder (for examle, in folder called “Dlls”) of your project when you try to call some dll functions you have got error message “Cannot find dll library”.
To solve this problem you need to set dll directory path. For this purpose let’s try to use WinAPI function SetDllDirectory. This function add directory to the search path used to locate DLLs for your application.
After calling SetDllDirectory, the DLL search path is:
  1. The directory from which the application loaded.
  2. The directory specified by the lpPathName parameter.
  3. The system directory. The name of this directory is System32.
  4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory.
  6. The directories that are listed in the PATH environment variable.
I use this function in Load event of my project.
public partial class MyForm : Form
{
       [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)]
       public static extern bool SetDllDirectory(String lpPathName);

       private void MyForm_Load(object sender, EventArgs e)
       {
              // Restores the default search order
              SetDllDirectory(null);

              // Add dll directory pathcsharp
              SetDllDirectory(AppDomain.CurrentDomain.BaseDirectory + "Dlls");csharp

             // Some code here
       }
}

First line restore default search paths of application and second line add new path for dll directory.
It’s very useful to store dll libraries in separate folder. Is help to structure files in project correctly and always find needed library very quickly.