StandardSwitcher does not show any content in its preview area if the selected docking window contains a WindowsFormsHost control. Based on http://www.actiprosoftware.com/community/thread/3528/image-on-standard-switcher-window I tried to override OnSelectedWindowChanged, extract a bitmap of the Forms control, convert it to a WPF bitmap, and assign it to the according StandardSwitcher element. This is my code so far:
public static class WinFormsWpfBitmapConversion
{
public static BitmapSource ToWpfBitmap(this System.Drawing.Bitmap bitmap)
{
using (var stream = new MemoryStream())
{
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Position = 0;
var result = new BitmapImage();
result.BeginInit();
result.CacheOption = BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze();
return result;
}
}
}
internal class WindowsFormsSwitcher : StandardSwitcher
{
public WindowsFormsSwitcher()
{
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
// creep through logical tree till preview border
var outerBorder = GetTemplateChild("outerBorder") as Border;
if (outerBorder == null)
return;
var dockPanel = outerBorder.Child as DockPanel;
if (dockPanel == null)
return;
if (dockPanel.Children == null || dockPanel.Children.Count < 3)
return;
var border1 = dockPanel.Children[2] as Border;
if (border1 == null)
return;
var grid = border1.Child as Grid;
if (grid == null)
return;
if (grid.Children == null || grid.Children.Count < 5)
return;
var border2 = grid.Children[4] as Border;
if (border2 == null)
return;
var shadow = border2.Child as DropShadowChrome;
if (shadow == null)
return;
var viewBox = shadow.Child as Viewbox;
if (viewBox == null)
return;
var border3 = viewBox.Child as Border;
if (border3 == null)
return;
var preview = border3.Child as DockingWindowPreview;
if (preview == null)
return;
_previewBorder = preview.Child as Border;
}
protected override void OnSelectedWindowChanged(DockingWindow oldValue, DockingWindow newValue)
{
if (SelectedWindow == null || _previewBorder == null)
{
base.OnSelectedWindowChanged(oldValue, newValue);
return;
}
// if window does not host a WindowsFormsHost call base method
var windowsFormsHost = SelectedWindow.Content as WindowsFormsHost;
if (windowsFormsHost == null)
{
base.OnSelectedWindowChanged(oldValue, newValue);
return;
}
// show image of WindowsFormsHost
var bitmapSource = GetBitmapSource(windowsFormsHost.Child);
var imageBrush = new ImageBrush { ImageSource = bitmapSource };
_previewBorder.Background = imageBrush;
// do not call base
}
BitmapSource GetBitmapSource(System.Windows.Forms.Control control)
{
var bitmap = new System.Drawing.Bitmap(control.Width, control.Height);
control.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
var bitmapSource = bitmap.ToWpfBitmap();
return bitmapSource;
}
private Border _previewBorder;
}
Unfortunately it does not work. Changes to _previewBorder have no effect on the view. May I ask you for your suggestions?