Phân Tích Khác Biệt Triển Khai Giao Diện Không Viền
Khi phát triển ứng dụng tìm kiếm tập tin trên nền .NET, việc lựa chọn giữa WinForms và Avalonia UI đặt ra nhiều thách thức kỹ thuật. Bài viết tập trung vào ba khía cạnh then chốt: xử lý thông điệp hệ thống, di chuyển cửa sổ không tiêu đề, và thay đổi kích thước giao diện không viền.
Xử Lý Thông Điệp Hệ Thống
Đăng ký phím tắt hệ thống thông qua API RegisterHotKey yêu cầu cơ chế bắt thông điệp khác biệt giữa hai framework:
[DllImport("user32.dll")]
static extern bool RegisterHotKey(IntPtr hWnd, int id, uint mod, uint vk);
// Đăng ký phím tắt Ctrl+Shift+S
RegisterHotKey(Handle, 1001, 0x0002 | 0x0004, (uint)Keys.S);
WinForms: Ghi đè WndProc
Triển khai xử lý thông điệp thông qua phương thức WndProc với cấu trúc tối ưu hiệu suất:
protected override void WndProc(ref Message msg)
{
if (msg.Msg == 0x0312 && msg.WParam.ToInt32() == 1001)
{
ToggleVisibility();
return;
}
base.WndProc(ref msg);
}
Avalonia: Hook API Hệ Thống
Sử dụng cơ chế hook của Win32 thông qua Win32Platform để tránh mất thông điệp:
private void SetupSystemHooks()
{
var platform = (Win32Platform)Application.Current.Platform!;
platform.AddWndProcHook(WndProcHook);
}
private IntPtr WndProcHook(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x0312 && wParam.ToInt32() == 1001)
{
ToggleVisibility();
handled = true;
}
return IntPtr.Zero;
}
Di Chuyển Cửa Sổ Không Viền
Thao tác kéo thả yêu cầu xử lý sự kiện chuột khác nhau ở mỗi framework:
WinForms: Đánh Lừa Hệ Thống
Sử dụng hằng số hệ thống để giả lập thao tác trên thanh tiêu đề:
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_DRAGMOVE = 0xF012;
[DllImport("user32.dll")]
private static extern int ReleaseCapture();
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
private void HeaderBar_PointerPressed(object sender, PointerPressedEventArgs e)
{
ReleaseCapture();
SendMessage(Handle, WM_SYSCOMMAND, SC_DRAGMOVE, 0);
}
Avalonia: API Tích Hợp Sẵn
Triển khai trực tiếp thông qua phương thức BeginMoveDrag:
private void HeaderBar_PointerPressed(object sender, PointerPressedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
BeginMoveDrag(e);
}
}
Thay Đổi Kích Thước Cửa Sổ
Quản lý vùng thao tác thay đổi kích thước khi không có viền cửa sổ:
WinForms: Xử Lý WM_NCHITTEST
Ghi đè WndProc để xác định vùng thao tác chuột:
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0084) // WM_NCHITTEST
{
var point = PointToClient(new Point(m.LParam));
var hitTest = CalculateResizeHitTest(point);
if (hitTest != 0) m.Result = (IntPtr)hitTest;
else base.WndProc(ref m);
return;
}
base.WndProc(ref m);
}
private int CalculateResizeHitTest(Point point)
{
const int borderThickness = 8;
var size = ClientSize;
if (point.X < borderThickness)
{
if (point.Y < borderThickness) return 13; // Góc trái trên
if (point.Y > size.Height - borderThickness) return 16; // Góc trái dưới
return 10; // Cạnh trái
}
// Tương tự cho các cạnh còn lại...
return 0;
}
Avalonia: Cấu Hình XAML
Thiết lập thuộc tính mở rộng vùng client trong file giao diện:
<Window
xmlns:platform="clr-namespace:Avalonia.Win32;assembly=Avalonia.Win32"
platform:WindowIconHelper.ExtendClientAreaToDecorations="True"
platform:WindowIconHelper.ExtendClientAreaChrome="NoSystemChrome"
platform:WindowIconHelper.TitleBarHeight="-1">
<!-- Nội dung giao diện -->
</Window>