Tag Archives: WPF

Adding many entries to an Observable collection in a performance friendly way

I was writing a WPF application which was polling a lot of web services in order to display stuff in a list. The items change infrequently but required constant polling in order to make sure that they stayed the same. The problem appeared when they suddenly changed a lot . You see, the built-in Observable collection does not like when you toy around with it a lot and will send tons of events. So, while my app mostly chugged along with a few new entries an hour, sometimes it got a thousand in one fell swoop – causing unresponsiveness.

I googled around a bit, and found this
article
, that while good did not help my situation. Since I cannot know when I’ll receive many entries, and I’d like to have a simple interface I have improved on this solution a bit.

Behold, the DeferEventObservableCollection:

public class DeferEventObservableCollection : ObservableCollection
{
	private readonly List<NotifyCollectionChangedEventArgs> deferredEvents = new List<NotifyCollectionChangedEventArgs>();
	private bool hasQueuedDispatcherUpdate = false;
	private readonly int threshold;
	private object syncRoot = new object();

	public DeferEventObservableCollection(int threshold = 10)
	{
		this.threshold = threshold;
	}
	
	protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
	{
		lock (syncRoot)
		{
			deferredEvents.Add(e);
			if (!hasQueuedDispatcherUpdate)
			{
				Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
				{
					lock (syncRoot)
					{
						if (deferredEvents.Count > treshold)
						{
							base.OnCollectionChanged(
								new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
						}
						else
						{
							foreach (var ev in deferredEvents)
							{
								base.OnCollectionChanged(ev);
							}
						}
						deferredEvents.Clear();
						hasQueuedDispatcherUpdate = false;
					}
				}));
			}
			hasQueuedDispatcherUpdate = true;
		}
	}
}

What I have made is a collection that will seamlessly handle the issue of suddenly getting a lot of changes in a more graceful way. Adding an item or removing it will catch the event that the observable collection normally fires and queue it up on the dispatcher queue. Since you normally get your items added in the dispatcher thread this event will then be deferred to later on in the same chunk of dispatcher work (or the next chunk). Events keep piling up in this queue and once it’s time to fire the events the collection will evaluate the size of the event list. If it is above some threshold value it will replace the events in the queue with a single Reset event. You’ll need to experiment with the threshold to find the optimum number, the 10 is a raw guess, and it will vary on how many listeners you have on your collection.

Being the concurrency-aware programmer that I am, I have added some extra measure of thread safety so that it cannot go haywire. When emptying the event queue, if another thread should attempt to add a new even to the queue, the lock will prevent this from blowing up in your face.

This simple drop-in replacement changed the performance on my application by several orders of magnitude, and I hope you can find it as useful as I did in your project!

Edit: I fixed the locking, it no longer locks on this which is bad form . Instead it locks on a syncroot as it should. Thanks @pheiberg for pointing it out!

Tagged , , , , ,

It’s quite possible to host a brand new shiny WPF control inside your smelly old MFC or even Win32 windows. It’s not particularly hard to do so, but you will need to do a few obscure things to make this work. Also, the intellisense that VS provides isn’t operational when working with C++/CLI. So you’ll pretty much have to know what you’re doing.

Similar code such as this can be found, but they often gloss over the details, such as how to deal with feeding the keyboard events to the child window, and how to make sure that the child window will receive tab events. I’ve included this as well, since you’ll probably want those things when integrating your new component.

First off, in your MFC project you’ll need to turn on support for common language runtime (the /clr flag) and you need to set the CLR-tread attribute to STA-thread in the project which ultimately hosts your .exe file. If you don’t do the STA-thread it will crash horribly and it will not be obvious why it has done so. In fact, the only hint is that it seems to crash even before it has a chance to be able to do so. That’s because the default setting is to handle the windows with multiple threads, something which WPF chokes on. The setting is found under Linker->Advanced.

For the sake of discussion lets say you have a dialog which extends the MFC class CDialog . You want to replace the contents of the window with a WPF control. First there is a few things that needs to be added, namely two references that needs to be kept in the dialog to keep the garbage collector from raining on our parade. In the header add two gcroot members:

gcroot m_hwndSource;
gcroot m_wpfControl;

Now to the more interesting bits, how to actually create an area for the WPF control to live in. What you actually need to do is to create something called a HwndSource . This object is a ‘real’ windows window and as such can receive windows messages and are actually understood by the windows system. A fundamental difference between WPF and Winforms/MFC/Win32 is that WPF does not have a HWND for every component that you create. It will only have one outer window and nothing more. This outer window is not created by itself, instead we need to provide such a window for WPF to live in. In some suitable place like the handler for WM_CREATE in your CDialog add this.

System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew System::Windows::Interop::HwndSourceParameters("MyWpfSourceWnd");
// This sets the position within the parent window
sourceParams->PositionX = 0;
sourceParams->PositionY = 0;
sourceParams->ParentWindow = System::IntPtr(this->GetSafeHwnd());
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD;

System::Windows::Interop::HwndSource^ source = gcnew System::Windows::Interop::HwndSource(*sourceParams);
MyWpfControl^ wpfControl = gcnew MyWpfControl();

// This creates sets the root visual of the interop component to out user control.
// As a sidenote, THIS is where it crashes if you have forgotten to set STA-thread.
source->RootVisual = wpfControl;

// Adds a keyboard hook!
source->AddHook(gcnew System::Windows::Interop::HwndSourceHook(ChildHwndSourceHook));

// This is the HWND of the interop component, should you choose to save it.
m_wpfChild = (HWND)source->Handle.ToPointer();
   
// This is important! If you do not save these the garbage collector eats them up!!
m_hwndSource = source;
m_wpfControl = wpfControl;

You might have noticed that we also added a hook to the window. This is needed, since if we do not do this your WPF control is never going to receive any keyboard events. The mouse however still works. This is a simple function outlined below:

System::IntPtr ChildHwndSourceHook(
    System::IntPtr /*hwnd*/, int msg,
    System::IntPtr /*wParam*/, System::IntPtr /*lParam*/, bool% handled)
{
    if (msg == WM_GETDLGCODE)
    {
        handled = true;
        // WANTCHARS = input boxes work
        // WANTTAB = tab order works
        // WANTALLKEYS = Enter key will work
        return System::IntPtr(DLGC_WANTCHARS | DLGC_WANTTAB |DLGC_WANTALLKEYS);
    }
    return System::IntPtr(0);
}

This is pretty much all you need to do. Note that there is nothing strange at ALL with the WPF usercontrol. No modifications needed, which also means that you can insert ANY of the cool WPF controls into your MFC application. Also, should you be stuck in Win32 country this works just as well, you just need to provide the parent HWND in another way than this->GetSafeHwnd() .

Now go out and create your frankensteinian interop apps to terrorize the neighborhood.

Tagged , , ,

I’ve recently had the dubious pleasure of getting to know C++/CLI and revisiting my good old buddy MFC. The task at hand was to integrate a WPF component into an existing MFC application. That task in itself is probably interesting enough to warrant it’s own post but suffice to say that I got this working properly. This means that we’ll end up with a class deriving CDialog that holds a WPF component inside it. Now we want to handle events. In WPF country, this is easy: add this to our WPF class:

public event EventHandler OnMyEvent;

And in our dialog we hold the WPF control in a gcroot<MyWPFControlClassName> . We also have a method we’d like to get called.

void MyDialogClass::OnEvent(System::Object ^sender, System::EventArgs ^args)
{
   // Do stuff
}

First off, what prompted this article is what does not work . You cannot from your unmanaged dialog class pass a pointer to your member function to your event like this.

wpfControl->OnMyEvent += gcnew System::EventHandler(
      this, 
      &MyNativeDialogClass::OnEvent);

This does not work, and it’s because your class is not a managed class since it’s not declared as ref class . The error message is also less than helpful. So how to solve this? You need a wrapper. Create this class somewhere in your project.

#pragma once

template<class T> ref class ManagedEventWrapper {
public:
   typedef void(T::*MemberFunction)(System::Object^ sender, System::EventArgs^ args);

   ManagedEventWrapper(T& host, MemberFunction function)
      : m_host (host)
      , m_function(function) 
   {
   }
   
   void OnEvent(System::Object ^sender, System::EventArgs ^args)
   {
      (m_host.*m_function)(sender, args);
   }

private:
   T& m_host;
   MemberFunction m_function;
};

If you then include this file in your MFC class, then you can subscribe to events like this:

wpfControl->OnMyEvent += gcnew System::EventHandler(
      gcnew ManagedEventWrapper<MyNativeDialogClass>(*this, &MyNativeDialogClass::OnEvent), 
      &ManagedEventWrapper<MyNativeDialogClass>::OnEvent);

This creates the neccessary layer of extra indirection around the native code to make the event handling work properly. You don’t need to save the reference to ManagedEventWraper since the reference is held by the System::EventHandler which makes sure it does not get garbage collected.

Tagged , , , ,
Follow