У меня есть WindowsFormsHost
, вложенный в WPF ScrollViewer, по какой-то причине после применения отсечения кажется, что WIndowsFormsHost
не заполняет все доступные пробелы, ie: элемент управления был перегружен.
Вот как это выглядит - обратите внимание, что есть много пустого пространства, которое действительно должно быть заполнено синим цветом.
Вот мой код в целом:
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);
}
А вот 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>
Обратите внимание, что в моем коде я наследую от WindowsFormsHostEx
, а не WindowsFormsHost
, поскольку при изменении размера Windows это приведет к отсечению элементов управления Winformcontrols, поэтому содержимое label
будет всегда оставаться видимым.
Если я использую WindowsFormsHost
, тогда все пробелы будут заполнены, но содержание label
ниже будет перекрыто. Тоже не то, что я хочу.
Код для WindowsFormsHostEx
получен из здесь .
Я не слишком уверен, что я делаю неправильно с приведенным выше кодом; как я могу это исправить?