첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ WindowsFormsHost 클래스 : WinForm 객체 사용시 스크롤 영역 클리핑 처리하기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


MainWindow.xaml

 

 

<Window x:Class="TestProject.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="800"

    Height="600"

    Title="WindowsFormsHost 클래스 : WinForm 객체 사용시 스크롤 영역 클리핑 처리하기"

    FontFamily="나눔고딕코딩"

    FontSize="16">

    <Border Margin="20" BorderThickness="1" BorderBrush="Black">

        <ScrollViewer>

            <StackPanel Name="stackPanel" />

        </ScrollViewer>

    </Border>

</Window>

 

 

MainWindow.xaml.cs

 

 

using System;

using System.Windows;

using System.Windows.Controls;

 

namespace TestProject

{

    /// <summary>

    /// 메인 윈도우

    /// </summary>

    public partial class MainWindow : Window

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainWindow()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainWindow()

        {

            InitializeComponent();

 

            Loaded += Window_Loaded;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 윈도우 로드시 처리하기 - Window_Loaded(sender, e)

 

        /// <summary>

        /// 윈도우 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            System.Drawing.Color[] colorArray = new System.Drawing.Color[]

            {

                System.Drawing.Color.Red,

                System.Drawing.Color.Green,

                System.Drawing.Color.Blue

            };

 

            for(int i = 0; i < 100; i++)

            {

                ScrollableWindowsFormsHost host = new ScrollableWindowsFormsHost();

 

                host.Width  = 100;

                host.Height = 100;

                host.Margin = new Thickness(10);

 

                System.Windows.Forms.UserControl control = new System.Windows.Forms.UserControl();

 

                control.BackColor = colorArray[i % 3];

 

                host.Child = control;

 

                this.stackPanel.Children.Add(host);

            }

        }

 

        #endregion

    }

}

 

 

WindowsFormsHost.cs

 

 

using System;

using System.ComponentModel;

using System.Runtime.InteropServices;

using System.Windows;

using System.Windows.Forms.Integration;

using System.Windows.Media;

using System.Windows.Controls;

 

/// <summary>

/// 스크롤 가능한 윈도우 폼 호스트

/// </summary>

[DesignTimeVisible(false)]

public class ScrollableWindowsFormsHost : WindowsFormsHost

{

    //////////////////////////////////////////////////////////////////////////////////////////////////// Import

    ////////////////////////////////////////////////////////////////////////////////////////// Static

    //////////////////////////////////////////////////////////////////////////////// Private

 

    #region 사각형 영역 생성하기 - CreateRectRgn(left, top, right, bottom)

 

    /// <summary>

    /// 사각형 영역 생성하기

    /// </summary>

    /// <param name="left">왼쪽 위치</param>

    /// <param name="top">위쪽 위치</param>

    /// <param name="right">오른쪽 위치</param>

    /// <param name="bottom">아래쪽 위치</param>

    /// <returns>사각형 영역 핸들</returns>

    [DllImport("gdi32.dll")]

    private static extern IntPtr CreateRectRgn(int left, int top, int right, int bottom);

 

    #endregion

    #region 윈도우 영역 설정하기 - SetWindowRgn(windowHandle, regionHandle, redraw)

 

    /// <summary>

    /// 윈도우 영역 설정하기

    /// </summary>

    /// <param name="windowHandle">윈도우 핸들</param>

    /// <param name="regionHandle">영역 핸들</param>

    /// <param name="redraw">다시 그리기 여부</param>

    /// <returns>처리 결과</returns>

    [DllImport("user32.dll", SetLastError = true)]

    private static extern int SetWindowRgn(IntPtr windowHandle, IntPtr regionHandle, bool redraw);

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Field

    ////////////////////////////////////////////////////////////////////////////////////////// Private

 

    #region Field

 

    /// <summary>

    /// 프리젠테이션 소스

    /// </summary>

    private PresentationSource presentationSource;

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Property

    ////////////////////////////////////////////////////////////////////////////////////////// Private

 

    #region 부모 스크롤 뷰어 - ParentScrollViewer

 

    /// <summary>

    /// 부모 스크롤 뷰어

    /// </summary>

    private ScrollViewer ParentScrollViewer { get; set; }

 

    #endregion

    #region 루트 비주얼 - RootVisual

 

    /// <summary>

    /// 루트 비주얼

    /// </summary>

    private Visual RootVisual

    {

        get

        {

            if(this.presentationSource == null)

            {

                this.presentationSource = PresentationSource.FromVisual(this);

            }

 

            return this.presentationSource.RootVisual;

        }

    }

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

    ////////////////////////////////////////////////////////////////////////////////////////// Public

 

    #region 생성자 - ScrollableWindowsFormsHost()

 

    /// <summary>

    /// 생성자

    /// </summary>

    public ScrollableWindowsFormsHost()

    {

        PresentationSource.AddSourceChangedHandler(this, sourceChangedEventHandler);

    }

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Method

    ////////////////////////////////////////////////////////////////////////////////////////// Protected

 

    #region 윈도우 위치 변경시 처리하기 - OnWindowPositionChanged(windowRect)

 

    /// <summary>

    /// 윈도우 위치 변경시 처리하기

    /// </summary>

    /// <param name="windowRect">윈도우 사각형</param>

    protected override void OnWindowPositionChanged(Rect windowRect)

    {

        base.OnWindowPositionChanged(windowRect);

 

        if(ParentScrollViewer == null)

        {

            return;

        }

 

        GeneralTransform generalTransform = RootVisual.TransformToDescendant(ParentScrollViewer);

 

        Rect scrollRect = new Rect(new Size(ParentScrollViewer.ViewportWidth, ParentScrollViewer.ViewportHeight));

 

        Rect intersectRect = Rect.Intersect(scrollRect, generalTransform.TransformBounds(windowRect));

 

        if(!intersectRect.IsEmpty)

        {

            generalTransform = ParentScrollViewer.TransformToDescendant(this);

 

            intersectRect = generalTransform.TransformBounds(intersectRect);

        }

        else

        {

            intersectRect = new Rect();

        }

 

        int x1 = (int)Math.Round(intersectRect.Left);

        int y1 = (int)Math.Round(intersectRect.Top);

        int x2 = (int)Math.Round(intersectRect.Right);

        int y2 = (int)Math.Round(intersectRect.Bottom);

 

        SetRegion(x1, y1, x2, y2);

    }

 

    #endregion

    #region 해제하기 - Dispose(disposing)

 

    /// <summary>

    /// 해제하기

    /// </summary>

    /// <param name="disposing">해제 여부</param>

    protected override void Dispose(bool disposing)

    {

        base.Dispose(disposing);

 

        if(disposing)

        {

            PresentationSource.RemoveSourceChangedHandler(this, sourceChangedEventHandler);

        }

    }

 

    #endregion

 

    ////////////////////////////////////////////////////////////////////////////////////////// Private

    //////////////////////////////////////////////////////////////////////////////// Event

 

    #region 소스 변경시 이벤트 핸들러 처리하기 - sourceChangedEventHandler(sender, e)

 

    /// <summary>

    /// 소스 변경시 이벤트 핸들러 처리하기

    /// </summary>

    /// <param name="sender">이벤트 발생자</param>

    /// <param name="e">이벤트 인자</param>

    private void sourceChangedEventHandler(object sender, SourceChangedEventArgs e)

    {

        ParentScrollViewer = FindParentScrollViewer();

    }

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////// Function

        

    #region 부모 스크롤 뷰어 찾기 - FindParentScrollViewer()

 

    /// <summary>

    /// 부모 스크롤 뷰어 찾기

    /// </summary>

    /// <returns>부모 스크롤 뷰어</returns>

    private ScrollViewer FindParentScrollViewer()

    {

        DependencyObject parentDependencyObject = this;

        ScrollViewer     parentScrollViewer     = null;

 

        while(parentDependencyObject != null)

        {

            parentScrollViewer = parentDependencyObject as ScrollViewer;

 

            if(parentScrollViewer != null)

            {

                break;

            }

 

            parentDependencyObject = LogicalTreeHelper.GetParent(parentDependencyObject);

        }

 

        return parentScrollViewer;

    }

 

    #endregion

    #region 영역 설정하기 - SetRegion(x1, y1, x2, y2)

 

    /// <summary>

    /// 영역 설정하기

    /// </summary>

    /// <param name="x1">X1 좌표</param>

    /// <param name="y1">Y1 좌표</param>

    /// <param name="x2">X2 좌표</param>

    /// <param name="y2">Y2 좌표</param>

    private void SetRegion(int x1, int y1, int x2, int y2)

    {

        SetWindowRgn(Handle, CreateRectRgn(x1, y1, x2, y2), true);

    }

 

    #endregion

}

 

------------------------------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker
TAG

댓글을 달아 주세요