当在数据网格中使用WindowsFormsHost时,我的控件超出了网格的可滚动区域。
我已经尝试使用这里提到的解决方案,ScrollViewer在WPF WindowsFormHost中不工作。
我也能够限制控件滚动区域,使用scrolllablewindowsformshost类。然而,发生的事情是我的Winforms控件(这是一个控件派生自Winforms组合框)将不会显示,除非我在单元格内单击两次(第一次单击聚焦在单元格上,第二次单击绘制我的组合框),这再次消失在窗口重绘。
从xaml: <toolkit:DataGridTemplateColumn>
<toolkit:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:HostedWinformsCombobox>
</controls:HostedWinformsCombobox>
</DataTemplate>
</toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>
ScrollableWindowsFormsHost.代码
//--------------------------------------------------------------------------------
/// <summary>Scroll handler manages the clipping of this windows forms host.</summary>
/// <param name="sender">Sender</param>
/// <param name="ea">Event argument</param>
private void ScrollHandler(Object sender, ScrollChangedEventArgs ea)
{
PresentationSource presentationSource = HwndSource.FromVisual(this);
if (presentationSource == null)
{
return;
}
Visual rootVisual = presentationSource.RootVisual;
if (rootVisual == null)
{
return;
}
ScrollViewer scrollViewer = (ScrollViewer)sender;
if (!scrollViewer.IsDescendantOf(rootVisual))
{
return;
}
// calculate the rect of scrollview with 0/0 at upper left corner of root visual
GeneralTransform transform = scrollViewer.TransformToAncestor(rootVisual);
Rect scrollRect = transform.TransformBounds(new Rect(0, 0, scrollViewer.ViewportWidth, scrollViewer.ViewportHeight));
// calculate the rect of the scrollable windows forms host instance with 0/0 at upper left corner of root visual
transform = this.TransformToAncestor(rootVisual);
Rect hostRect = transform.TransformBounds(new Rect(this.Padding.Left, this.Padding.Right,
this.RenderSize.Width, this.RenderSize.Height));
// calculate the intersection of the two rect
Rect intersectRect = Rect.Intersect(scrollRect, hostRect);
Int32 topLeftX = 0;
Int32 topLeftY = 0;
Int32 bottomRightX = 0;
Int32 bottomRightY = 0;
if (intersectRect != Rect.Empty)
{
// calculate the HRGN points with 0/0 at upper left corner of scrollable windows forms host instance
//topLeftX = (Int32)(intersectRect.TopLeft.X - hostRect.TopLeft.X);
//topLeftY = (Int32)(intersectRect.TopLeft.Y - hostRect.TopLeft.Y);
//bottomRightX = (Int32)(intersectRect.BottomRight.X - hostRect.TopLeft.X);
//bottomRightY = (Int32)(intersectRect.BottomRight.Y - hostRect.TopLeft.Y);
//modified from original function - this one draws it correctly without drawing over the title bar etc.
topLeftX = (Int32)(intersectRect.TopLeft.X);
topLeftY = (Int32)(intersectRect.TopLeft.Y);
bottomRightX = (Int32)(intersectRect.BottomRight.X);
bottomRightY = (Int32)(intersectRect.BottomRight.Y);
}
// because the CreateRectRgn / SetWindowRgn api calls are slow we call them only if it has a visual effect
if (_topLeftX != topLeftX || _topLeftY != topLeftY || _bottomRightX != bottomRightX || _bottomRightY != bottomRightY)
{
_topLeftX = topLeftX;
_topLeftY = topLeftY;
_bottomRightX = bottomRightX;
_bottomRightY = bottomRightY;
// create HRGN object and set it to the windows forms host instance
IntPtr hrgn = CreateRectRgn(_topLeftX, _topLeftY, _bottomRightX, _bottomRightY);
SetWindowRgn(this.Handle, hrgn, true);
// I tried the following to fix the issue, but neither ones worked
this.UpdateLayout(); //doesn't work
this.Child.Show(); //doesn't work
}
}
这段代码对我来说很有效。
public class DataGridWindowsFormsHost : WindowsFormsHost
{
private Int32 _topLeftX = -1;
private Int32 _topLeftY = -1;
private Int32 _bottomRightX = -1;
private Int32 _bottomRightY = -1;
private const int _titleBarHeight = 25; // must leave the space for the title bar in DataGrid
private const int _scrollbarHeight = 5; // must leave space for horizontal scroll area in the bottom
//--------------------------------------------------------------------------------
/// <summary>Creates a DataGridWindowsFormsHost.</summary>
public DataGridWindowsFormsHost()
{
// Register the event handler
EventManager.RegisterClassHandler(typeof(ScrollViewer), ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(ScrollHandler));
}
[DllImport("GDI32.DLL", EntryPoint = "CreateRectRgn")]
private static extern IntPtr CreateRectRgn(Int32 x1, Int32 y1, Int32 x2, Int32 y2);
[DllImport("User32.dll", SetLastError = true)]
private static extern Int32 SetWindowRgn(IntPtr hWnd, IntPtr hRgn, Boolean bRedraw);
private DataGrid _dGrid;
public DataGrid DGrid
{
get
{
if(_dGrid == null)
{
PresentationSource presentationSource = HwndSource.FromVisual(this);
Visual rootVisual = presentationSource.RootVisual;
_dGrid = VisualTreeHelperExt.FindChildByName<DataGrid>(_rootVisual, "myDataGrid") as DataGrid;
}
return _dGrid;
}
}
//--------------------------------------------------------------------------------
/// <summary>Scroll handler manages the clipping of this windows forms host.</summary>
/// <param name="sender">Sender</param>
/// <param name="ea">Event argument</param>
private void ScrollHandler(Object sender, ScrollChangedEventArgs ea)
{
PresentationSource presentationSource = HwndSource.FromVisual(this);
Visual rootVisual = presentationSource.RootVisual;
GeneralTransform transform = DGrid.TransformToAncestor(rootVisual);
// leave the space for title bar and horizontal scrollbar at the bottom
Rect gridRect = transform.TransformBounds(new Rect(0, _titleBarHeight,
DGrid.ActualWidth - _scrollbarHeight, DGrid.ActualHeight - _titleBarHeight));
transform = this.TransformToAncestor(_rootVisual);
// find the rect of the hosting control
Rect hostRect = transform.TransformBounds(new Rect(this.Padding.Left, this.Padding.Right,
this.RenderSize.Width, this.RenderSize.Height));
var intersectRect = Rect.Intersect(gridRect, hostRect);
Int32 topLeftX = 0;
Int32 topLeftY = 0;
Int32 bottomRightX = 0;
Int32 bottomRightY = 0;
if (intersectRect != Rect.Empty)
{
// calculate the HRGN points with 0/0 at upper left corner of scrollable windows forms host instance
topLeftX = (Int32)(intersectRect.TopLeft.X - hostRect.TopLeft.X);
topLeftY = (Int32)(intersectRect.TopLeft.Y - hostRect.TopLeft.Y);
bottomRightX = (Int32)(intersectRect.BottomRight.X - hostRect.TopLeft.X);
bottomRightY = (Int32)(intersectRect.BottomRight.Y - hostRect.TopLeft.Y);
}
// because the CreateRectRgn / SetWindowRgn api calls are slow we call them only if it has a visual effect
if (_topLeftX != topLeftX || _topLeftY != topLeftY || _bottomRightX != bottomRightX || _bottomRightY != bottomRightY)
{
_topLeftX = topLeftX;
_topLeftY = topLeftY;
_bottomRightX = bottomRightX;
_bottomRightY = bottomRightY;
// create HRGN object and set it to the windows forms host instance
IntPtr hrgn = CreateRectRgn(_topLeftX, _topLeftY, _bottomRightX, _bottomRightY);
SetWindowRgn(this.Handle, hrgn, true);
}
}
}