button1은 CustomPanel 하위 목록으로 들어가면서 추가 될 필드를 지정할 수 있습니다.
TableLayout 에서 Row, RowSpan 등의 속성이 추가되는 것이 궁금하여 찾아본 내용 정리입니다.
CustomPanel 하위 목록에 대해서 디자이너에서 보여줄 필드를 생성 가능
Panel 외에도 다른 컨트롤을 상속받아서도 가능합니다.
내부적으로 Dictionary 처리를 통해 값을 별도로 관리할 수 있습니다.
ProvideProperty 는 여러 개를 사용할 수 있습니다.
IExtenderProvider 를 상속받아야 하며 Setter와 Getter를 구현해주어야 사용 가능합니다.
아래는 예시 코드입니다.
using System.Collections.Generic;
using System.ComponentModel; //IExtenderProvider
using System.Windows.Forms;
namespace WindowsFormsApp6
{
//해당 이름 사용. Get, Set 구현 필수
//CustomField 이기때문에 GetCustomField(Control, 타입), SetCustomField(Control) 메소드 필요.
[ProvideProperty("CustomField", typeof(Control))]
class CustomPanel : Panel, IExtenderProvider
{
private readonly Dictionary<Control, int> fieldDict = new Dictionary<Control, int>();
public bool CanExtend(object extendee)
{
Control control = extendee as Control;
if (control == null)
{
return false;
}
//조건에 따라 전체 컴포넌트에 붙을 수 있음.
return control.Parent == this; //자식 컴포넌트에만 붙여주기
}
[DisplayName("CustomField")] //없으면 클래스명의 필드로 이름 지정됨.
public int GetCustomField(Control control)
{
if (fieldDict.TryGetValue(control, out int value))
{
return value;
}
return 0; //default value
}
public void SetCustomField(Control control, int value)
{
fieldDict[control] = value;
}
}
}
using System;
using System.IO;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string folderPath = Path.Combine(Directory.GetCurrentDirectory(), "targetFolder");
string[] files = Directory.GetFiles(folderPath);
DateTime now = DateTime.Now.AddDays(-3); //3일 전 파일까지 검출용.
foreach (string file in files)
{
FileInfo fileInfo = new FileInfo(file);
//A < B = 1, A == B = 0, A > B = -1
if (DateTime.Compare(now, fileInfo.LastWriteTime) > 0) //기준보다 오래된 파일 삭제
{
fileInfo.Delete();
}
}
}
}
}
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Text;
using System.IO;
namespace ApplyFontFromCode
{
public partial class Form1 : Form
{
private PrivateFontCollection privateFontCollection;
public Form1()
{
InitializeComponent();
//해당 리소스가 해제되면 폰트 오류가 발생되므로 전역 변수로 선언 필요.
privateFontCollection = new PrivateFontCollection();
privateFontCollection.AddFontFile(Path.Combine(Application.StartupPath, "ChangwonDangamAsac-Bold_0712.ttf"));
SetControlFont(this);
}
private void SetControlFont (Control parent)
{
foreach (Control child in parent.Controls) //모든 하위 컨트롤들에 대해서 적용시켜줍니다.
{
child.Font = new Font(privateFontCollection.Families[0], child.Font.Size, child.Font.Style);
if (child.Controls.Count > 0) //panel, groupbox 와 같이 하위 컨트롤이 더 있는 경우도 적용시켜줍니다.
{
SetControlFont(child);
}
}
}
}
}
namespace FormStyleNoneResize
{
public partial class TestForm : FormParent
{
public TestForm()
{
InitializeComponent();
this.SetTitle(label1); //타이틀 (마우스 움직임 등 설정)
this.SetCloseButton(button1); //닫기 이벤트 추가
}
}
}
FormParent Class
using System;
using System.Drawing;
using System.Windows.Forms;
namespace FormStyleNoneResize
{
public partial class FormParent : Form
{
//https://docs.microsoft.com/ko-kr/windows/win32/inputdev/wm-nchittest
private const int WM_NCHITTEST = 0x84; //마우스 커서 위치가 크기 조절 가능한 부분에 있는 경우
private const int HTCLIENT = 1;
private const int HTLEFT = 10;
private const int HTRIGHT = 11;
private const int HTTOP = 12;
private const int HTTOPLEFT = 13;
private const int HTTOPRIGHT = 14;
private const int HTBOTTOM = 15;
private const int HTBOTTOMLEFT = 16;
private const int HTBOTTOMRIGHT = 17;
private const int GRIP = 5; //리사이즈 잡는 영역 크기
private Point prePosition;
private Point mouseDownPoint;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCHITTEST)
{
base.WndProc(ref m);
if ((int)m.Result == HTCLIENT)
{
Point position = this.PointToClient(Cursor.Position);
bool left = position.X <= GRIP;
bool right = this.Width - GRIP <= position.X;
bool top = position.Y <= GRIP;
bool bottom = this.Height - GRIP <= position.Y;
if (left && top) m.Result = (IntPtr)HTTOPLEFT;
else if (right && top) m.Result = (IntPtr)HTTOPRIGHT;
else if (left && bottom) m.Result = (IntPtr)HTBOTTOMLEFT;
else if (right && bottom) m.Result = (IntPtr)HTBOTTOMRIGHT;
else if (left) m.Result = (IntPtr)HTLEFT;
else if (right) m.Result = (IntPtr)HTRIGHT;
else if (top) m.Result = (IntPtr)HTTOP;
else if (bottom) m.Result = (IntPtr)HTBOTTOM;
}
return;
}
base.WndProc(ref m); //다른 처리를 위한 기존 콜백 다시 호출해주기
}
public FormParent()
{
InitializeComponent();
}
//마우스 이벤트가 발생할 타이틀바를 등록합니다.
protected void SetTitle(Control titleControl)
{
titleControl.MouseDoubleClick += new MouseEventHandler(titleControl_MouseDoubleClick);
titleControl.MouseDown += new MouseEventHandler(titleControl_MouseDown);
titleControl.MouseMove += new MouseEventHandler(titleControl_MouseMove);
}
//최소화 버튼을 등록합니다.
protected void SetMinimumButton(Button button)
{
button.Click += new EventHandler(this.button_minimum_Click);
}
//최대화 버튼을 등록합니다.
protected void SetMaximumButton(Button button)
{
button.Click += new EventHandler(this.button_maximum_Click);
}
protected void SetCloseButton(Button button)
{
button.Click += new EventHandler(this.button_close_Click);
}
private void titleControl_MouseDoubleClick(object sender, MouseEventArgs e) //상단 타이틀 더블 클릭
{
if (e.Button != MouseButtons.Left) //왼쪽 버튼만 사용
{
return;
}
if (WindowState != FormWindowState.Maximized)
{
SetMaximize();
}
else
{
SetNormal();
}
}
private void titleControl_MouseDown(object sender, MouseEventArgs e) //상단 타이틀 클릭 시 움직일 준비
{
if (e.Button != MouseButtons.Left) //왼쪽 버튼만 사용
{
return;
}
mouseDownPoint = new Point(e.X, e.Y);
}
private void titleControl_MouseMove(object sender, MouseEventArgs e) //상단 타이틀을 통한 이동
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left) //왼쪽 버튼이 눌린 경우만 움직여줍니다.
{
this.Left += e.X - mouseDownPoint.X;
this.Top += e.Y - mouseDownPoint.Y;
}
}
private void button_minimum_Click(object sender, EventArgs e) //최소화 버튼
{
WindowState = FormWindowState.Minimized;
}
private void button_maximum_Click(object sender, EventArgs e) //최대화 버튼
{
if (WindowState != FormWindowState.Maximized)
{
SetMaximize();
}
else
{
SetNormal();
}
}
private void SetNormal() //기존 사이즈로 변경
{
this.Location = prePosition; //크기 변경 시 원 위치로 복귀
this.WindowState = FormWindowState.Normal;
}
private void SetMaximize() //최대화
{
Screen screen = Screen.FromControl(this); //현재 Form과 가장 가까운 Screen 찾기.
prePosition = this.Location; //노멀화 복귀 좌표값
this.Location = screen.Bounds.Location; //위치 지정
this.MaximizedBounds = new Rectangle(0, 0, screen.WorkingArea.Width, screen.WorkingArea.Height); //최대화 크기 변경
this.WindowState = FormWindowState.Maximized;
}
//종료 버튼
private void button_close_Click(object sender, EventArgs e)
{
Close();
}
}
}
ZipFile 클래스 사용을 위해선 System.IO.Compression.FileSystem 참조가 필요합니다.
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression; //ZipFile 에 필요
using System.Windows.Forms;
namespace WindowsFormsApp13
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) //zip 생성
{
string workFolder = Application.StartupPath;
string targetDirectory = Path.Combine(workFolder, "TestFiles");
string savePath = Path.Combine(workFolder, "Zipfile.zip");
if (File.Exists(savePath)) //기존 파일은 제거
{
File.Delete(savePath);
}
ZipFile.CreateFromDirectory(targetDirectory, savePath);
Process.Start(workFolder); //폴더 열어서 확인
}
private void button2_Click(object sender, EventArgs e) //zip 해제
{
string workFolder = Application.StartupPath;
string targetPath = Path.Combine(workFolder, "Zipfile.zip");
string saveFolder = Path.Combine(workFolder, "unZip");
if (Directory.Exists(saveFolder)) //기존 파일은 제거
{
Directory.Delete(saveFolder, true);
}
ZipFile.ExtractToDirectory(targetPath, saveFolder);
Process.Start(workFolder); //폴더 열어서 확인
}
}
}
파일 압축 및 풀기 결과
그 밖에도 다른 라이브러리들이 있는데, NuGet 에서 받아서 사용이 가능합니다.
GPT에서 제공한 표를 남겨두겠습니다.
- GPT 정리 내용
라이브 러리 암호화 포맷 속도 최신 유지장점 요약 (2025년 10월 06일 기준!)
라이브러리
암호화
포맷
속도
최신 유지
장점 요약
System.IO.Compression
❌
ZIP
✅ 빠름
✅ 최신
.NET 내장, 간단
DotNetZip (Ionic.Zip)
✅
ZIP
⚪ 보통
❌ 구버전
암호 ZIP 지원
SharpZipLib
✅
ZIP, TAR, GZIP 등
⚪ 보통
✅ 유지보수 중
다양한 포맷
SharpCompress
⚠️ 제한적
ZIP, 7z, TAR 등
⚪ 보통
✅ 최신
스트리밍 지원
SevenZipSharp
✅ AES
7z
⚠️ 느림
⚪ 부분적
고압축, 보안
DotNetZip 간단 사용법 예시
using Ionic.Zip;
// 압축
using (var zip = new ZipFile())
{
zip.Password = "1234"; // 암호 설정
zip.AddDirectory(@"C:\TestSource");
zip.Save(@"C:\Result.zip");
}
// 해제
using (var zip = ZipFile.Read(@"C:\Result.zip"))
{
zip.Password = "1234";
zip.ExtractAll(@"C:\Extracted", ExtractExistingFileAction.OverwriteSilently);
}