I have a WindowsFormsHost
nested inside a WPF ScrollViewer, for some reason, after applying clipping it seems that the WIndowsFormsHost
is not filling up all of the available spaces, ie: the control has been overclipped.
Here's how it looks like-- note that there are a lot of white space, which really should be filled with blue color.
Here's my code in totality:
public class DummyWinformControl : WindowsFormsHostEx /* WindowsFormsHost */
{
public DummyWinformControl()
{
var panel = new System.Windows.Forms.Panel();
panel.Dock = DockStyle.Fill;
panel.BackColor = System.Drawing.Color.Blue;
Child = panel;
}
}
/// <summary>
/// https://stackoverflow.com/a/18084481
/// </summary>
public class WindowsFormsHostEx : WindowsFormsHost
{
private PresentationSource _presentationSource;
public WindowsFormsHostEx()
{
PresentationSource.AddSourceChangedHandler(this, SourceChangedEventHandler);
}
protected override void OnWindowPositionChanged(Rect rcBoundingBox)
{
base.OnWindowPositionChanged(rcBoundingBox);
if (ParentScrollViewer == null)
return;
GeneralTransform tr = RootVisual.TransformToDescendant(ParentScrollViewer);
var scrollRect = new Rect(new Size(ParentScrollViewer.ViewportWidth, ParentScrollViewer.ViewportHeight));
var intersect = Rect.Intersect(scrollRect, tr.TransformBounds(rcBoundingBox));
if (!intersect.IsEmpty)
{
tr = ParentScrollViewer.TransformToDescendant(this);
intersect = tr.TransformBounds(intersect);
}
else
intersect = new Rect();
int x1 = (int)Math.Round(intersect.Left);
int y1 = (int)Math.Round(intersect.Top);
int x2 = (int)Math.Round(intersect.Right);
int y2 = (int)Math.Round(intersect.Bottom);
SetRegion(x1, y1, x2, y2);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
PresentationSource.RemoveSourceChangedHandler(this, SourceChangedEventHandler);
}
private void SourceChangedEventHandler(Object sender, SourceChangedEventArgs e)
{
ParentScrollViewer = FindParentScrollViewer();
}
private ScrollViewer FindParentScrollViewer()
{
DependencyObject vParent = this;
ScrollViewer parentScroll = null;
while (vParent != null)
{
parentScroll = vParent as ScrollViewer;
if (parentScroll != null)
break;
vParent = LogicalTreeHelper.GetParent(vParent);
}
return parentScroll;
}
private void SetRegion(int x1, int y1, int x2, int y2)
{
SetWindowRgn(Handle, CreateRectRgn(x1, y1, x2, y2), true);
}
private Visual RootVisual
{
get
{
if (_presentationSource == null)
_presentationSource = PresentationSource.FromVisual(this);
return _presentationSource.RootVisual;
}
}
private ScrollViewer ParentScrollViewer { get; set; }
[DllImport("User32.dll", SetLastError = true)]
static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw);
[DllImport("gdi32.dll")]
static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
}
And here's the MainWindow.XAML:
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid ScrollViewer.CanContentScroll="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<GroupBox Header="abc" Grid.Row="0" BorderThickness="1" Width="400" Height="600">
<local:DummyWinformControl />
</GroupBox>
<Label Content="Hello world" Grid.Row="1"/>
</Grid>
</ScrollViewer>
Note that in my code, I am inheriting from WindowsFormsHostEx
and not WindowsFormsHost
, because doing so will apply clipping on the Winformcontrols when I am resizing the Windows, so that the label
content will always remain visible.
If I use WindowsFormsHost
then all the spaces will be filled up, but the label
content below will be overlaid. Also not what I want.
The code for WindowsFormsHostEx
is obtained from here.
I'm not too sure what I do wrong with the above code; how can I fix it?