在数据网格中使用WindowsFormsHost,会溢出滚动区域



当在数据网格中使用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);
        }
    }
}

相关内容

  • 没有找到相关文章

最新更新