ReoGrid Forum

Fast and powerful .NET Spreadsheet Component

You are not logged in.

Announcement

This forum has been archived and no longer accepts new user registrations. Please report your questions, problems, and feedback to the issue page of ReoGrid on GitHub. Thank you for your cooperation.

https://github.com/unvell/ReoGrid/issues

#1 2017-05-08 14:01:42

Frank
Member
Registered: 2017-05-08
Posts: 1

Modified WindowsFormsHost for using Winform version of ReoGrid

I am working on a WPF project that need table controls which behaves like excel, with all of its keyboard navigation. Fortunately I found here... However the WPF version is not as robust as I like. I eventually fall back to the Winform version, which is quite useable.

I get some modified WindowsFormsHost code from internet, then modify it further to handle scaling issues when in a ScrollViewer. I would like post its code here, in case anyone interested.

    public class WindowsFormsHostEx : WindowsFormsHost
    {
        private PresentationSource _presentationSource;
        private double scalingFactor = 1;

        public WindowsFormsHostEx()
        {
            PresentationSource.AddSourceChangedHandler(this, SourceChangedEventHandler);
        }

        protected override void OnWindowPositionChanged(Rect rcBoundingBox)
        {
            rcBoundingBox = new Rect(rcBoundingBox.X / scalingFactor,
                                     rcBoundingBox.Y / scalingFactor,
                                     rcBoundingBox.Width / scalingFactor,
                                     rcBoundingBox.Height / scalingFactor);
            base.OnWindowPositionChanged(rcBoundingBox);

            if (ParentScrollViewer == null)
                return;

            GeneralTransform tr = RootVisual.TransformToDescendant(ParentScrollViewer);
            var scrollRect = new Rect(new System.Windows.Size(ParentScrollViewer.ViewportWidth, ParentScrollViewer.ViewportHeight));

            var t = tr.TransformBounds(rcBoundingBox);

            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) * scalingFactor);
            int y1 = (int)(Math.Round(intersect.Top) * scalingFactor);
            int x2 = (int)(Math.Round(intersect.Right) * scalingFactor);
            int y2 = (int)(Math.Round(intersect.Bottom) * scalingFactor);

            SetRegion(x1, y1, x2, y2);
        }

        public void Release()
        {
            Dispose(true);
        }

        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)
                {
                    var source = PresentationSource.FromVisual(this);
                    scalingFactor = source.CompositionTarget.TransformToDevice.M11;
                    _presentationSource = source;
                }

                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);
    }

Just make sure invoking Release() method when the table is not needed. WinForm has to be manually disposed when hosted in a WPF app. Otherwise you will see that the 'User Object' keep increasing till it hits 10000. :-)

Offline

#2 2017-05-09 00:53:14

Jingwood
Moderator
From: jing at reogrid.net
Registered: 2014-06-03
Posts: 615

Re: Modified WindowsFormsHost for using Winform version of ReoGrid

Nice! thanks!

Offline

Board footer

Powered by FluxBB