2

在数据网格中使用 WindowsFormsHost 时,我的控件超出了网格的可滚动区域。

我尝试使用此处提到的解决方案,ScrollViewer 在 WPF WindowsFormHost 中不起作用

我还可以使用 ScrollableWindowsFormsHost 类将控件限制在滚动区域。然而,除非我在单元格内单击两次(第一次单击单元格上的焦点,第二次单击绘制我的组合框),否则我的 Winforms 控件(这是从 Winforms 组合框派生的控件)不会显示,它在窗口重绘时再次消失.

来自 xml:

            <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
        }
    }
4

1 回答 1

1

这段代码对我有用。

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);
        }
    }
}
于 2013-03-18T15:41:55.133 回答