KeiStory

728x90
반응형

WPF WindowsFormsHost 사용 시 Scroll 문제

 

WPF 로 개발을 할때 종종 WindowsFormsHost 를 이용해 Winfrom Control 을 올려놓고 사용할 때가 있습니다.

그런데 화면에 내용이 많아 스크롤이 생긴 경우 스크롤을 하게되면

WindowsFormsHost 가 WPF 컨트롤을 가리면서 Overflow 되어 표시되는 경우가 생깁니다.

이때는 Scrolling 을 해결한 새로운 WindowsFormHost 를 만들어 사용하면 해결됩니다.

아래 코드를 보면 알수 있듯이 Win32 API를 사용하여 HWND 영역을 새로 그려주도록 하면됩니다.

아래 코드를 참고하여 ScrollViewerWindowsFormsHost 를 추가합니다.

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
using System.Windows.Media;

namespace Yournamespace
{
    public class ScrollViewerWindowsFormsHost : WindowsFormsHost
    {
        private PresentationSource _presentationSource;

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

        protected override void OnWindowPositionChanged(Rect rcBoundingBox)
        {
            base.OnWindowPositionChanged(rcBoundingBox);

            if (ParentScrollViewer == null)
                return;

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

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

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

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

        Visual RootVisual
        {
            get
            {
                if (_presentationSource == null)
                    _presentationSource = PresentationSource.FromVisual(this);

                return _presentationSource.RootVisual;
            }
        }

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

 

XAML 단에서 WindowsFormsHost 대신 ScrollViewerWindowsFormsHost  를 사용하면

Scrolling 시 화면을 가리는 문제가 해결됩니다.

 

 

728x90

공유하기

facebook twitter kakaoTalk kakaostory naver band