Using VisualTreeHelper.GetDrawing to get around the Z-Order limitation when hosting Windows Forms controls

Jaime Rodriguez
On Windows Phone, Windows Presentation Foundation, Silverlight and Windows 7

Using VisualTreeHelper.GetDrawing to get around the Z-Order limitation when hosting Windows Forms controls

  • Comments 2

Several times I have had needed to put WPF content in front of  Windows Forms control hosted in a WPF app...

Unfortunately, this is a limitation in the interop story, WindowsFormsHost elements are always drawn on top, and don't get affected by z-order ...

The first time I did this, I was working with an imaging company, so it was easy as their activex rendered onto a bitmap already.. so we used that as a workaround: create a bitmap, and then 'replace' the control with the bitmap at specific times/triggers..

The next time, I tried to use the same workaround .. but this time, I wrote some 'ugly' code to make a simple winforms control render into a bitmap ... [trust me it was ugly, took me a day+, used interop, ec.] ...   Now, I see this post from LLobo telling me there was an API for this ...  way to make me feel dumber than usual :( ...

So, I am putting it here so no one else misses it like I did,  also as a reference as now I have to email Robert -sorry man - to tell him to replace our old code :) The API is VisualTreeHelper.GetDrawing..   Wrote the simplest  test, here is kinda what it looks like [will do for a quick airspace demo :) ]

 

 

Explanation of the screen above:
The Left hand side is a WindowsFormsHost  control hosting a MonthCalendar Windows Forms controls. . The RHS is a Rectangle witha DrawingBrush of the WindowsFormsHost in the LHS...   Across both UIElements, there is supposed to be a red rectangle overlayed [imagine this could be any other element or a flying animation, etc.] ...  Notice that on the Left, the Red rectangle is behind the WindowsFormsHost. . on the right, you get the right visual experience. .
You could easily use this strategy to swap the WindowsFormsHost in and out ...  don't you think??

The code is trivial,  I packaged it inside a Dispatcher callback - I don't think it is absolutely needed, but felt safer, trying to make sure windowsformshost has been drawn] ....

void Window1_Loaded(object sender, RoutedEventArgs e)
{
Matrix m =
PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformToDevice;
double dx = m.M11;
double dy = m.M22;

System.Windows.Forms.MonthCalendar mc = new System.Windows.Forms.MonthCalendar();
mc.Width = (int)(wfHost.Width * dx);
mc.Height = (int)(wfHost.Height * dy);
wfHost.Child = mc;

this.Dispatcher.BeginInvoke (System.Windows.Threading.DispatcherPriority.Background ,
new DispatcherOperationCallback(delegate
{
DrawingGroup dg = VisualTreeHelper.GetDrawing( wfHost );
DrawingBrush db = new DrawingBrush ( dg );
db.TileMode = TileMode.None;
db.Stretch = Stretch.None;
rect.Fill= db ;

return null;
} ), null );

}

 

Full sample is here.

I tested with several custom windows forms controls seems to work ... That said, I could not get Lester's demo to work with the IE frame ...
I believe this same code will work for Win32 interop (HwndHost) but did not test it, if you try it and it does not work ping me..

  • That's really nice sample, but the problem is still exists. You are using WindowsFormHost *graphics* as brush for your rectangle, so the hosted application will not interact with the user.

  • Yes Tamir, you are right.. this does not solve the problem.. it is just a way to create the illusion that the problem is not there..  Swapping the right control in and out is not hard. I did not write a sample for the swap, because it is controls specific, some people would want to swap on click, or focus, mouse enter, etc..  

Page 1 of 1 (2 items)