ScrollViewer is not working in WPF WindowsFormHost

前端 未结 6 896
半阙折子戏
半阙折子戏 2020-12-14 23:00

\"enterI have WindowsFormHost with a RichTextBox in my WPF form, i have given ScrollViewer for

6条回答
  •  情歌与酒
    2020-12-14 23:54

    We are using multiple ScrollViewers and also a ViewBox so none of the mentioned solutions worked for us. So here is our soloution which can also deal with different DPI settings.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Forms.Integration;
    using System.Windows.Media;
    using System.Windows.Threading;
    
    
    namespace XYZ
    {
    
        public class ClippingWindowsFormsHost : WindowsFormsHost
        {
            private readonly DispatcherTimer _updateTimer;
    
            private Rect _bounds;
    
            private PresentationSource _source;
    
            public ClippingWindowsFormsHost()
            {
                PresentationSource.AddSourceChangedHandler(this, _sourceChangedEventHandler);
    
                _updateTimer = new DispatcherTimer(DispatcherPriority.Render);
                _updateTimer.Tick += _updateTick;
                _updateTimer.Interval = TimeSpan.FromMilliseconds(100);
            }
    
            private void _updateTick(object sender, EventArgs e)
            {
                _updateTimer.Stop();
    
                if (_source == null)
                    return;
    
    
                // Get the Rect of the scrollviewer on screen.
                Rect scrollRect = _getScrollRect();
    
                // apply dpi settings
                scrollRect = _scaleDpi(scrollRect);
    
                if (scrollRect.Width > 0 && scrollRect.Height > 0) // if the rect is valid...
                {
                    int x1 = (int) Math.Ceiling(scrollRect.X);
                    int y1 = (int) Math.Ceiling(scrollRect.Y);
                    int x2 = (int) Math.Ceiling(scrollRect.Right);
                    int y2 = (int) Math.Ceiling(scrollRect.Bottom);
    
                    SetWindowRgn(Handle, CreateRectRgn(x1, y1, x2, y2), true);
                }
                else
                    SetWindowRgn(Handle, CreateRectRgn(0, 0, 0, 0), true);
    
            }
    
            private Rect _scaleDpi(Rect rect)
            {
                if (_source.CompositionTarget != null)
                {
                    Matrix transformToDevice = _source.CompositionTarget.TransformToDevice;
                    if (!transformToDevice.IsIdentity)
                    {
                        Point scaledSize = transformToDevice.Transform(new Point(rect.Width, rect.Height));
                        rect = new Rect(rect.X, rect.Y, scaledSize.X, scaledSize.Y);
                    }
                }
    
                return rect;
            }
    
            [DllImport("User32.dll", SetLastError = true)]
            private static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw);
    
            [DllImport("gdi32.dll")]
            private static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
    
            protected override void OnWindowPositionChanged(Rect rcBoundingBox)
            {
                base.OnWindowPositionChanged(rcBoundingBox);
                _updateClipping(rcBoundingBox);
            }
    
            private void _updateClipping(Rect bounds)
            {
                if (_source == null || _bounds == bounds)
                    return;
    
                _bounds = bounds;
    
                // Only update clipping in certain intervals, otherwise splitpanels can create huge cpu load
                _updateTimer.Stop();
                _updateTimer.Start();
            }
    
            private Rect _getScrollRect()
            {
                ScrollViewer scrollViewer = _getTopScrollViewer();
    
                // Get the screenposition of the scrollviewer
                Point topLeft = scrollViewer.PointToScreen(new Point(0, 0));
                Point bottomRight = scrollViewer.PointToScreen(new Point(scrollViewer.ViewportWidth, scrollViewer.ViewportHeight));
    
                Rect scrollRect = new Rect(topLeft, bottomRight);
    
    
    
                // Get "this" position and use it to offset the scrollrect
                // because that is basically the scrolled distance
                Point myPosition = PointToScreen(new Point());
                scrollRect.Offset(-myPosition.X, -myPosition.Y);
    
                return scrollRect;
            }
    
            private ScrollViewer _getTopScrollViewer()
            {
                DependencyObject parent = this;
                ScrollViewer lastViewer = null;
                while ((parent = VisualTreeHelper.GetParent(parent)) != null)
                {
                    ScrollViewer viewer = parent as ScrollViewer;
                    if (viewer != null)
                        lastViewer = viewer;
                }
    
                return lastViewer;
            }
    
            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);
    
                if (disposing)
                {
                    _updateTimer.Stop();
                    PresentationSource.RemoveSourceChangedHandler(this, _sourceChangedEventHandler);
                }
            }
    
            private void _sourceChangedEventHandler(object sender, SourceChangedEventArgs e)
            {
                _updateTimer.Stop();
                _source = e.NewSource;
            }
        }
    }
    

提交回复
热议问题