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 =
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 ,
DrawingGroup dg = VisualTreeHelper.GetDrawing( wfHost );
DrawingBrush db = new DrawingBrush ( dg );
db.TileMode = TileMode.None;
db.Stretch = Stretch.None;
rect.Fill= db ;
} ), 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..