C# WinForm에서 컨트롤 크기 조절 기능 구현

윈폼 애플리케이션 개발 시, 사용자 인터페이스의 유연한 조정을 위해 컨트롤의 경계를 드래그하여 크기를 변경하는 기능이 필요할 수 있습니다. 아래는 DataGridViewPanel 등 다양한 컨트롤에 대해 마우스로 왼쪽, 오른쪽, 위, 아래 또는 모든 방향으로 크기 조절이 가능한 확장 메서드를 제공하는 예제입니다. 사용 방법은 간단합니다. 폼 로드 시 각 컨트롤에 해당 메서드를 호출하여 이벤트를 연결하면 됩니다. private void Form1_Load(object sender, EventArgs e) { panelLeft.SetResizeHandler(this, ResizeDirection.Left); panelRight.SetResizeHandler(this, ResizeDirection.Right); panelTop.SetResizeHandler(this, ResizeDirection.Top); panelBottom.SetResizeHandler(this, ResizeDirection.Bottom); dataGridView1.SetResizeHandler(this, ResizeDirection.All); } 다음은 핵심 로직을 포함한 전체 코드입니다. 기본적으로 마우스 위치를 기반으로 컨트롤의 경계선 근처인지 판단하고, 드래그 시 크기 조정을 처리하며, 최소/최대 크기 제한도 지원합니다. using System; using System.Drawing; using System.Windows.Forms; namespace ResizeControlHelper { public static class ControlExtensions { public static void SetResizeHandler(this Control control, Form owner, ResizeDirection direction, Size? maxSize = null, Size? minSize = null) { new ResizeManager(control, owner, direction, maxSize, minSize); } } public enum ResizeDirection { Left, Right, Top, Bottom, All } public class ResizeManager { private readonly Control targetControl; private readonly Form parentForm; private readonly ResizeDirection direction; private readonly Size maxLimit; private readonly Size minLimit; private bool isDragging; private ResizeDirection currentDirection; public ResizeManager(Control ctrl, Form form, ResizeDirection dir, Size? max, Size? min) { targetControl = ctrl; parentForm = form; direction = dir; maxLimit = max ?? new Size(1000, 1000); minLimit = min ?? new Size(100, 100); // 이벤트 연결 targetControl.MouseDown += OnMouseDown; targetControl.MouseMove += OnMouseMove; targetControl.MouseUp += OnMouseUp; targetControl.MouseLeave += OnMouseLeave; // 초기 커서 설정 if (dir == ResizeDirection.All) targetControl.Cursor = Cursors.SizeAll; else if (dir == ResizeDirection.Left || dir == ResizeDirection.Right) targetControl.Cursor = Cursors.SizeWE; else if (dir == ResizeDirection.Top || dir == ResizeDirection.Bottom) targetControl.Cursor = Cursors.SizeNS; } private void OnMouseDown(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left) return; if (direction == ResizeDirection.All) { var pos = Control.MousePosition; var screenLoc = parentForm.PointToScreen(targetControl.Location); // 왼쪽 경계 확인 if (pos.X >= screenLoc.X - 5 && pos.X <= screenLoc.X + 5 && pos.Y >= screenLoc.Y) currentDirection = ResizeDirection.Left; // 위쪽 경계 확인 else if (pos.Y >= screenLoc.Y - 5 && pos.Y <= screenLoc.Y + 5 && pos.X >= screenLoc.X) currentDirection = ResizeDirection.Top; // 오른쪽 경계 확인 else if (pos.X >= screenLoc.X + targetControl.Width - 5 && pos.X <= screenLoc.X + targetControl.Width + 5 && pos.Y >= screenLoc.Y) currentDirection = ResizeDirection.Right; // 아래쪽 경계 확인 else if (pos.Y >= screenLoc.Y + targetControl.Height - 5 && pos.Y <= screenLoc.Y + targetControl.Height + 5 && pos.X >= screenLoc.X) currentDirection = ResizeDirection.Bottom; else return; isDragging = true; targetControl.Capture = true; } else { isDragging = true; currentDirection = direction; } } private void OnMouseMove(object sender, MouseEventArgs e) { if (!isDragging) return; var mousePos = Control.MousePosition; var screenLoc = parentForm.PointToScreen(targetControl.Location); switch (currentDirection) { case ResizeDirection.Left: if (mousePos.X < screenLoc.X + targetControl.Width - minLimit.Width) UpdateSize(-e.X, 0); break; case ResizeDirection.Right: if (mousePos.X > screenLoc.X + targetControl.Width + minLimit.Width) UpdateSize(e.X, 0); break; case ResizeDirection.Top: if (mousePos.Y < screenLoc.Y + targetControl.Height - minLimit.Height) UpdateSize(0, -e.Y); break; case ResizeDirection.Bottom: if (mousePos.Y > screenLoc.Y + targetControl.Height + minLimit.Height) UpdateSize(0, e.Y); break; default: break; } } private void UpdateSize(int widthDelta, int heightDelta) { var newWidth = targetControl.Width + widthDelta; var newHeight = targetControl.Height + heightDelta; if (newWidth < minLimit.Width || newWidth > maxLimit.Width || newHeight < minLimit.Height || newHeight > maxLimit.Height) return; if (widthDelta != 0) { if (currentDirection == ResizeDirection.Left) { targetControl.Width = newWidth; targetControl.Left -= widthDelta; } else { targetControl.Width = newWidth; } } if (heightDelta != 0) { if (currentDirection == ResizeDirection.Top) { targetControl.Height = newHeight; targetControl.Top -= heightDelta; } else { targetControl.Height = newHeight; } } } private void OnMouseUp(object sender, MouseEventArgs e) { isDragging = false; targetControl.Capture = false; targetControl.Cursor = Cursors.Default; } private void OnMouseLeave(object sender, EventArgs e) { if (targetControl.Cursor == Cursors.SizeWE || targetControl.Cursor == Cursors.SizeNS) targetControl.Cursor = Cursors.Default; } } } 이 구현은 여러 컨트롤에 대해 동일한 동작을 적용할 수 있도록 확장 가능하며, 스레드 안전성과 크기 제약 조건을 고려해 설계되었습니다. 실제 사용 시 `minSize`와 `maxSize`를 통해 화면 내 정합성을 유지할 수 있습니다.

태그: WinForms C# UI resizing Control extension Mouse event handling

6월 27일 23:24에 게시됨