나의 개발일지
WinUi 3 Full Custom Window And TitleBar 본문
NuGet Package
App.xaml.cs
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
namespace AppTest
{
public partial class App : Application
{
public App()
{
this.InitializeComponent();
}
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
m_window = new MainWindow();
m_window.ExtendsContentIntoTitleBar = true;
m_window.Activate();
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(m_window);
Microsoft.UI.WindowId windowId =
Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);
var appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
if (appWindow.Presenter is OverlappedPresenter p)
{
p.SetBorderAndTitleBar(false, false);
p.IsResizable = false;
}
}
private Window m_window;
}
}
MainWindow.xaml
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="AppTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AppTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winuiex="using:WinUIEx"
mc:Ignorable="d">
<Window.SystemBackdrop>
<winuiex:TransparentTintBackdrop/>
</Window.SystemBackdrop>
<local:GridMain x:Name="Grid_Main" Margin="0" Padding="7" Background="Transparent" PointerMoved="Grid_Main_PointerMoved" PointerPressed="Grid_Main_PointerPressed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="Grid_TitleBar" Grid.Column="0" Grid.Row="0" Margin="0" Padding="0" Background="#B6BBC4" DoubleTapped="Grid_TitleBar_DoubleTapped"
PointerPressed="Grid_TitleBar_PointerPressed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" Margin="0" Tapped="Grid_Minimize_Tapped"
PointerEntered="Grid_PointerEntered" PointerExited="Grid_PointerExited">
<FontIcon Foreground="#656565" Glyph="" FontSize="12"/>
</Grid>
<Grid Grid.Column="2" Margin="0" Tapped="Grid_Maximize_Tapped"
PointerEntered="Grid_PointerEntered" PointerExited="Grid_PointerExited">
<FontIcon x:Name="FI_Maximize" Foreground="#656565" Glyph="" FontSize="12"/>
</Grid>
<Grid Grid.Column="3" Margin="0" Tapped="Grid_Close_Tapped"
PointerEntered="Grid_PointerEntered" PointerExited="Grid_PointerExited">
<FontIcon Foreground="#656565" Glyph="" FontSize="12"/>
</Grid>
</Grid>
<Frame x:Name="ContentFrame" Background="#FFFFFFFF" Grid.Column="0" Grid.Row="1"/>
</local:GridMain>
</Window>
MainWindow.xaml.cs
using Microsoft.UI;
using Microsoft.UI.Input;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Windows.Graphics;
using Windows.UI;
using WinRT.Interop;
namespace AppTest
{
public sealed partial class MainWindow : Window
{
private Microsoft.UI.Windowing.AppWindow _appWindow;
private OverlappedPresenter _appWindow_overlapped;
private DisplayArea _displayArea;
private int _Grid_Main_Padding;
private int _realWindowMinWidth, _realWindowMinHeight;
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPos(out POINT lpPoint);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetAsyncKeyState(int vKey);
const int VK_LBUTTON = 0x01;
private bool IsLeftMouseButtonPressed()
{
return GetAsyncKeyState(VK_LBUTTON) & 0x8000 != 0;
}
#region [| Get Cursor Icon Using Cursor Position (마우스 위치 기반 아이콘 가져오기)|]
private InputSystemCursor GetCursorShape(POINT mousePosition)
{
if (mousePosition.X < _appWindow.Position.X + _Grid_Main_Padding)
{
if (mousePosition.Y < _appWindow.Position.Y + 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNorthwestSoutheast);
}
else if (mousePosition.Y > _appWindow.Position.Y + _appWindow.Size.Height - 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNortheastSouthwest);
}
else
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeWestEast);
}
}
else if (mousePosition.X > _appWindow.Position.X + _appWindow.Size.Width - _Grid_Main_Padding)
{
if (mousePosition.Y < _appWindow.Position.Y + 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNortheastSouthwest);
}
else if (mousePosition.Y > _appWindow.Position.Y + _appWindow.Size.Height - 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNorthwestSoutheast);
}
else
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeWestEast);
}
}
else if (mousePosition.Y < _appWindow.Position.Y + _Grid_Main_Padding)
{
if (mousePosition.X < _appWindow.Position.X + 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNorthwestSoutheast);
}
else if (mousePosition.X > _appWindow.Position.X + _appWindow.Size.Width - 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNortheastSouthwest);
}
else
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNorthSouth);
}
}
else if (mousePosition.Y > _appWindow.Position.Y + _appWindow.Size.Height - _Grid_Main_Padding)
{
if (mousePosition.X < _appWindow.Position.X + 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNortheastSouthwest);
}
else if (mousePosition.X > _appWindow.Position.X + _appWindow.Size.Width - 2 * _Grid_Main_Padding)
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNorthwestSoutheast);
}
else
{
return InputSystemCursor.Create(InputSystemCursorShape.SizeNorthSouth);
}
}
else
{
return InputSystemCursor.Create(InputSystemCursorShape.Arrow);
}
}
#endregion
#region [| Get Hex To Color (색상코드 Color로 변환) |]
public static Color GetColor(string hex)
{
hex = hex.Replace("#", string.Empty);
if (hex.Length == 6)
{
hex = "FF" + hex;
}
byte a = (byte)(Convert.ToUInt32(hex.Substring(0, 2), 16));
byte r = (byte)(Convert.ToUInt32(hex.Substring(2, 2), 16));
byte g = (byte)(Convert.ToUInt32(hex.Substring(4, 2), 16));
byte b = (byte)(Convert.ToUInt32(hex.Substring(6, 2), 16));
return Color.FromArgb(a, r, g, b);
}
#endregion
public MainWindow()
{
this.InitializeComponent();
using (var manager = WinUIEx.WindowManager.Get(this))
{
manager.Width = 500;
manager.Height = 500;
}
IntPtr hWnd = WindowNative.GetWindowHandle(this);
WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
_appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(wndId);
_realWindowMinWidth = _appWindow.Size.Width;
_realWindowMinHeight = _appWindow.Size.Height;
_appWindow_overlapped = (OverlappedPresenter)_appWindow.Presenter;
_appWindow_overlapped.IsMaximizable = false;
if (_appWindow is not null)
{
_displayArea = DisplayArea.GetFromWindowId(wndId, DisplayAreaFallback.Nearest);
if (_displayArea is not null)
{
// Open Window Center
// 윈도우 화면 중앙으로
var position = _appWindow.Position;
position.X = ((_displayArea.WorkArea.Width - _appWindow.Size.Width) / 2);
position.Y = ((_displayArea.WorkArea.Height - _appWindow.Size.Height) / 2);
_appWindow.Move(position);
}
}
_Grid_Main_Padding = (int)Grid_Main.Padding.Top;
}
#region [| Side Cursor Change (테두리 마우스 아이콘 변환) |]
private void Grid_Main_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (!_appWindow_overlapped.IsMaximizable)
{
GridMain gridMain = sender as GridMain;
POINT mousePosition;
GetCursorPos(out mousePosition);
gridMain.ChangeCursor(GetCursorShape(mousePosition));
}
}
#endregion
#region [| Side Cursor Change Width Height (테두리 마우스 아이콘 변환) |]
private async void Grid_Main_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (sender is GridMain gridMain && e.OriginalSource == sender)
{
if (e.GetCurrentPoint(gridMain).Properties.IsLeftButtonPressed)
{
int windowWidth, windowHeight;
using (var manager = WinUIEx.WindowManager.Get(this))
{
windowWidth = (int)manager.Width;
windowHeight = (int)manager.Height;
}
int realWindowWidth = _appWindow.Size.Width;
int realWindowHeight = _appWindow.Size.Height;
POINT windowPosition = new POINT { X = _appWindow.Position.X, Y = _appWindow.Position.Y };
POINT pressedPosition = new POINT { X = (int)e.GetCurrentPoint(gridMain).Position.X, Y = (int)e.GetCurrentPoint(gridMain).Position.Y };
bool isLeft = pressedPosition.X <= 2 * _Grid_Main_Padding;
bool isTop = pressedPosition.Y <= 2 * _Grid_Main_Padding;
bool isOnlyWidth = !isTop && pressedPosition.Y <= windowHeight - 2 * _Grid_Main_Padding;
bool isOnlyHeight = !isLeft && pressedPosition.X <= windowWidth - 2 * _Grid_Main_Padding;
int padding_x = windowWidth - pressedPosition.X;
int padding_y = windowHeight - pressedPosition.Y;
int width, height;
POINT mousePosition;
POINT windowMovePostion = new POINT();
while (IsLeftMouseButtonPressed())
{
GetCursorPos(out mousePosition);
if (isOnlyWidth)
{
width = isLeft ? realWindowWidth + windowPosition.X - mousePosition.X + pressedPosition.X : mousePosition.X - windowPosition.X + padding_x;
height = realWindowHeight;
windowMovePostion.X = isLeft ? mousePosition.X - pressedPosition.X : windowPosition.X;
windowMovePostion.Y = windowPosition.Y;
}
else if (isOnlyHeight)
{
width = realWindowWidth;
height = isTop ? realWindowHeight + windowPosition.Y - mousePosition.Y + pressedPosition.Y : mousePosition.Y - windowPosition.Y + padding_y;
windowMovePostion.X = windowPosition.X;
windowMovePostion.Y = isTop ? mousePosition.Y - pressedPosition.Y : windowPosition.Y;
}
else
{
width = isLeft ? realWindowWidth + windowPosition.X - mousePosition.X + pressedPosition.X : mousePosition.X - windowPosition.X + padding_x;
height = isTop ? realWindowHeight + windowPosition.Y - mousePosition.Y + pressedPosition.Y : mousePosition.Y - windowPosition.Y + padding_y;
windowMovePostion.X = isLeft ? mousePosition.X - pressedPosition.X : windowPosition.X;
windowMovePostion.Y = isTop ? mousePosition.Y - pressedPosition.Y : windowPosition.Y;
}
await Task.Run(() => {
_appWindow.MoveAndResize(new RectInt32(
_realWindowMinWidth > width ? _appWindow.Position.X : windowMovePostion.X,
_realWindowMinHeight > height ? _appWindow.Position.Y : windowMovePostion.Y,
_realWindowMinWidth > width ? _realWindowMinWidth : width,
_realWindowMinHeight > height ? _realWindowMinHeight : height
));
});
}
_appWindow_overlapped = (OverlappedPresenter)_appWindow.Presenter;
}
}
}
#endregion
#region [| Move Window Using TitleBar (윈도우 이동) |]
private void Grid_TitleBar_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (sender is Grid grid && e.OriginalSource == sender)
{
if (e.GetCurrentPoint(grid).Properties.IsLeftButtonPressed)
{
POINT mousePosition;
POINT mouseDownPosition;
var position = _appWindow.Position;
GetCursorPos(out mousePosition);
mouseDownPosition.X = mousePosition.X - position.X;
mouseDownPosition.Y = mousePosition.Y - position.Y;
while (IsLeftMouseButtonPressed())
{
GetCursorPos(out mousePosition);
position.X = mousePosition.X - mouseDownPosition.X;
position.Y = mousePosition.Y - mouseDownPosition.Y;
_appWindow.Move(position);
}
}
}
}
#endregion
#region [| TitleBar DoubleTapped (TitleBar 더블클릭) |]
private void Grid_TitleBar_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (e.OriginalSource == sender)
{
if (_appWindow_overlapped.IsMaximizable)
{
Grid_Main.Padding = new Thickness(_Grid_Main_Padding);
_appWindow_overlapped.Restore();
_appWindow_overlapped.IsMaximizable = false;
FI_Maximize.Glyph = "\uE922";
}
else
{
Grid_Main.Padding = new Thickness(0);
_appWindow_overlapped.Maximize();
_appWindow_overlapped.IsMaximizable = true;
FI_Maximize.Glyph = "\uE923";
}
}
}
#endregion
#region [| Window Minimize (윈도우 최소화) |]
private void Grid_Minimize_Tapped(object sender, RoutedEventArgs e)
{
_appWindow_overlapped.Minimize();
}
#endregion
#region [| Window Maximize (윈도우 최대화) |]
private void Grid_Maximize_Tapped(object sender, RoutedEventArgs e)
{
if (_appWindow_overlapped.IsMaximizable)
{
Grid_Main.Padding = new Thickness(_Grid_Main_Padding);
_appWindow_overlapped.Restore();
_appWindow_overlapped.IsMaximizable = false;
FI_Maximize.Glyph = "\uE922";
}
else
{
Grid_Main.Padding = new Thickness(0);
_appWindow_overlapped.Maximize();
_appWindow_overlapped.IsMaximizable = true;
FI_Maximize.Glyph = "\uE923";
}
}
#endregion
#region [| Close Window (윈도우 닫기) |]
private void Grid_Close_Tapped(object sender, RoutedEventArgs e)
{
this.Close();
}
#endregion
#region [| Gird Mouse Over Background Color Change (마우스 오버 효과) |]
private Grid _grid;
private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e)
{
_grid = sender as Grid;
_grid.Background = new SolidColorBrush(GetColor("#40000000"));
}
private void Grid_PointerExited(object sender, PointerRoutedEventArgs e)
{
_grid = sender as Grid;
_grid.Background = new SolidColorBrush(GetColor("#00000000"));
}
#endregion
}
public class GridMain : Grid
{
public GridMain()
{
}
public void ChangeCursor(InputCursor cursor)
{
this.ProtectedCursor = cursor;
}
public InputCursor GetCursor()
{
return this.ProtectedCursor;
}
}
}
결과
'어플리케이션 > WinUi(C#)' 카테고리의 다른 글
VisualStudio 2022 WinUi 3 윈도우 여러개 디버깅 오류(multi window debug Error In App.xaml.cs) (0) | 2023.12.28 |
---|---|
WinUi 3 마우스로 창 이동 (0) | 2023.12.22 |
WinUi 3 포커스(focus 비슷한)? 확인 (0) | 2023.12.22 |
WinUi 3 새로운 창 만들기 (0) | 2023.12.22 |
WinUi 3 GridView 사용법 (0) | 2023.12.13 |