Dailycode.info

Short solution for short problems

Fire and event from a sub thread to the main thread in WPF

This small example shows you how to simply fire an event from a sub thread, capture it In the main thread and handle it in WPF.

The demo application (Attached to this post) simply starts a sub thread. In this thread we generate some random numbers and sent them back to the main thread. The main thread will show these numbers in a list.

First let’s investigate the main thread.

I’m using 2 private objects in my main thread:

private Dispatcher _uiDispatcher;

Thread _workerThread;

 

The _uiDispatcher will be used to store the main thread dispatcher in. The workerThread is the thread that will be used to handle the subroutine.

When I initiate the mainform, I will store the dispatcher of the main thread in the _uiDispatcher.

// Call from the main thread  

public void UseThisThreadForEvents()

{     

_uiDispatcher = Dispatcher.CurrentDispatcher;

} 

       

public MainWindow()

{

InitializeComponent();

       UseThisThreadForEvents();

}

 

So when the program starts, we have the dispatcher of the main thread that will be responsible to update the UI stored in a variable.

On the main form there is a button, when clicked it will start the sub thread.

private void button1_Click(object sender, RoutedEventArgs e)

{

    ThreadStart start;

    Worker worker = new Worker();

    worker.OnValueSent += new Worker.SentValueHandler(worker_OnValueSent);

    start = delegate()

    {

        worker.SentValuesEvery2Seconds();

    };

 

    // Create the thread and kick it started!

    _workerThread = new Thread(start);

    _workerThread.Priority = ThreadPriority.Lowest;

    _workerThread.Start();

           

}

 

In my worker class I declared an event that will be fired every 2 seconds. This event will be captured in the main thread and handled by the worker_OnValueSent method.

So here is where we will have to check in which thread we are and if needed invoke the dispatcher of the main thread so we can update the UI without invoking every control separately.

public delegate void OnValueSentDelegate(List<int> list);

 

void worker_OnValueSent(List<int> list)

{

    if (Dispatcher.CurrentDispatcher != _uiDispatcher)

    {

        _uiDispatcher.BeginInvoke(new OnValueSentDelegate(worker_OnValueSent), list);

 

    }

    else

    {

        listView1.Items.Add(list[0]);

        listView1.Items.Add(list[1]);

        listView1.Items.Add(list[2]);

    }

}

 

Simple logic written here. When the event is fired, we check if the dispatcher equals the _uiDispatcher (Dispatcher of the main thread). If not, we invoke the main thread dispatcher and use a delegate method to call the OnValueSent method.

So that’s how we do it.

For the people who need it, here the simple code of the worker class:

public class Worker

{

    public delegate void SentValueHandler(List<int> list);

 

    public event SentValueHandler OnValueSent;

 

    public void SentValuesEvery2Seconds()

    {

        int test = 0;

        while (test < 5)

        {

            Thread.Sleep(2000);

            if (OnValueSent != null)

            {

                Random rd = new Random();

 

                OnValueSent(new List<int>() { rd.Next(0, 1000), rd.Next(0, 1000), rd.Next(0, 1000) });

            }

            test++;

        }

    }

}

 

And here is a screenshot to give you an idea of what it does and how it looks.

 

 

WpfApplication1.zip (50.11 kb)


Multi-Threading or Cross threading and accessing controls from seperate threads in WPF

I started to build my first real WPF application. It’s a former windows application that I’m rebuilding and improving using WPF and WCF. Former it was Windows forms and Web services.

One of the first problems I encountered was when I was experimenting with multithreading. I start my main thread and from there I will start a background thread. This background thread will start sub thread of its own. Still not a big issue, until I wanted to report the status from my background thread to my main thread. At this point it’s slightly different in WPF then it was in windows forms. And for some reason Microsoft decided to hide some methods in Visual Studio, so this makes it even harder.

The base article from which I constructed my application can be found is Avalon Threading by Tyler Barton and Nick Kramer.

So it all starts when you start a process in a separate thread, I decided to start a background worker thread process like this:

 

/// <summary>

/// Loads the devices and starts Polling

/// </summary>

public void LoadDevices(List<ThinClient> thinClients)

{

    BackgroundWorker bw = new BackgroundWorker();         

    // this allows our worker to report progress during work        

    bw.WorkerReportsProgress = true;         

    // what to do in the background thread        

    bw.DoWork += new DoWorkEventHandler(delegate(object o, DoWorkEventArgs args)

        {

            LoadDevicesInThread(thinClients);       

        });         

   

    bw.RunWorkerAsync();

           

}

 

The actual work is done in the LoadDevicesInThread function. This function will loop over a list of TCP devices and will try to poll them, using a poll time out of 2 seconds. We do not want this to block the main thread, so that’s why it’s handled in the background. Still after each device I want the background thread to report the status to my GUI in the main thread.

That’s why I created these 3 methods. The background worker process is started in a sub class, where I created an event that will be raised whenever I want to log something back to the GUI.

 

public delegate void LogHandler(string type, string message);

 

public event LogHandler Log;

 

protected void OnLog(string type, string message)

{

    if (Log != null)

    {

        Log(type, message);

    }

}

 

So every time I call the OnLog method, the Log event  will be raised and captured by the GUI. Here were I do the binding to the event in the main window:

 

_ourDevices.Log += new Devices.LogHandler(_ourDevices_Log);

 

So the LogHandler will handle the loggings coming from the background thread and pass them to the GUI. This is where the tricky bit comes in. In Windows forms we had to call the InvokeRequired method, but when you look for this or something like this, you will find nothing in intellisense. Why you may ask. Because for WPF the InvokeRe quired doesn’t exists but has a “replacement” called CheckAccess. They decided to hide this method from the Visual Studio intellisense.  So when you want to invoke a control from a separate thread, this is the way it’s done:

 

public delegate void LogMessageDelegate(string type, string message);

 

void _ourDevices_Log(string type, string message)

{

    if (lstLogItems.CheckAccess())

    {

        lstLogItems.Items.Add(new InfoMessage(type, message));

    }

    else

    {

        lstLogItems.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Send, new LogMessageDelegate(this._ourDevices_Log),type, message);

    }

}

 

So here you can see that when the ListView called lstLogItems is accessed from a separate thread, he will end up in the else and do a begininvoke. He will use the delegate function to accomplish this and pass the parameters to it.

So I hope it become a little clearer this way. I posted an extension method on my blog for windows forms cross threading: http://www.dailycode.info/Blog/post/2011/10/12/Setting-the-property-of-a-control-from-a-seperate-thread-using-an-extension-method.aspx. You can try to rewrite this for WPF, if the need comes I will do it and post this on the Blog.

 


Directory copy(program attached to this post can be downloaded)

On request I created a small program that can copy one directory(including subdirectoies and files) to another directory. Nothing special, windows can do that. But The requirement was that only files created after a certain date needed to be copied.
It can be usefull for backup strategies or archiving.
Here a screenshot of this program.
 

 
Feel free to ask for the source code. Here a little snippet (This is a recursive function that loops over all files and directories. This functino is called in a seperate thread, so its not blocking the main thread and it can be stopped at all times.):
 
private void CopyDirStructure(string path, string searchdir)
{
    try
    {
        bool noOutput=false;
        if (GetOutputSize() > 2147400000)
        {
            SetOutput("\n!!!rest concatinated, to many files...!!!\n");
            noOutput=true;
        }
 
        DirectoryInfo dir = new DirectoryInfo(path);
        DirectoryInfo[] subDirs = dir.GetDirectories();
        FileInfo[] files = dir.GetFiles();
        
        int dept = 0;
 
        if (dir.FullName != searchdir)
        {
            if (files.Length > 0)
            {
                CreateDirAtDest(dir, noOutput);
            }
        }
        
        
        
            
        decimal dSize = 0;
        foreach (FileInfo fi in files)
        {
            bool bCopy = true;
            
            if (UseModifyDate())
            {
                if (fi.LastWriteTime < GetModifyDate())
                {
                    bCopy = false;
                }
            }
            if (bCopy)
            {
                if (CopyFileToDest(fi.FullName.ToString(), noOutput))
                {
                    dSize += Math.Round((decimal)fi.Length / 1024, 0, MidpointRounding.ToEven);
                    totalFileCount++;
                }
            }
        }
 
        
        
        totalSize += dSize;
       
        if (subDirs != null)
        {
            dept++;
            foreach (DirectoryInfo sd in subDirs)
            {
                CopyDirStructure(path + @"\\" + sd.Name, searchdir);
                totalDirCount++;
            }
        }
 
        SetDirCount(totalDirCount);
        SetFileCount(totalFileCount);
        SetSize(totalSize);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message.ToString());
    }
}
The controls are updated after each file, because the copy is running in a seperate thread,
be sure that you invoke the controls before trying to update them:
 
public void SetFileCount(int c)
{
    if (this.lbltotal.InvokeRequired)
    {
        this.lbltotal.BeginInvoke(
            new MethodInvoker(
            delegate() { SetFileCount(c); }));
    }
    else
    {
        this.lbltotal.Text = c.ToString() + " files";
    }
}

Download the program here:

CopyFiles.zip (62.17 kb)


Directory structure generator version 1.1

I made some adjustements to the directory structure generator which have lead to new version. The major change is that I do the generation in a seperate thread. Now I can update the info during the process, the main thread is not blocked. It is also possible to stop the porcess whenever you like.

I added some extra features which can be nice. E.g. sorting on date, show modifydate in result, ...

Here is a screenshots of the latest version:

The exe file and source files can be requested.

You can read here how it all started.