1. 程式人生 > >WPF設計の自定義窗體

WPF設計の自定義窗體

mar 事件委托 左右 com vat esp pbo 定義 覆蓋

原文:WPF設計の自定義窗體

效果圖如下:

技術分享圖片

實現思路:

1.繼承Window類

2.為自定義的CustomWindow類設計窗體樣式(使用Blend很方便!)

3.為窗體增加最大最小化和關閉按鈕,並實現鼠標拖拽改變窗體大小(使用Derek Bartram的WindowResizer.dll庫)

代碼說明:

1.繼承Window類

創建CustomWindow類,繼承自System.Window

技術分享圖片代碼 public class CustomWindow : Window
{
public CustomWindow()
{
// 加載樣式
InitializeStyle();

// 加載事件委托
this.Loaded += delegate { InitializeEvent(); };

// 解決最大化覆蓋任務欄問題
this.SourceInitialized += new EventHandler(win_SourceInitialized);
}
}

技術分享圖片代碼 <src:CustomWindow
x:Class="windowStyle1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:windowStyle1"
Title="CustomWindow"
Height="358" Width="649" AllowsTransparency="True" WindowStyle="None">

2.為自定義的CustomWindow類設計窗體樣式

窗體樣式的設計可以使用Expression Blend來進行可視化開發,非常方便

技術分享圖片

Blend會自動生成樣式的xmal文件:

技術分享圖片代碼 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Luna">

<ControlTemplate x:Key="WindowTemplateKey" TargetType="{x:Type Window}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
<ResizeGrip x:Name="WindowResizeGrip" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsTabStop="false" Visibility="Collapsed"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ResizeMode" Value="CanResizeWithGrip"/>
<Condition Property="WindowState" Value="Normal"/>
</MultiTrigger.Conditions>
<Setter Property="Visibility" TargetName="WindowResizeGrip" Value="Visible"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>

3.為窗體增加最大最小化和關閉按鈕,並實現鼠標拖拽改變窗體大小

按鈕事件比較簡單,通過分別為三個按鈕添加Click事件即可

技術分享圖片代碼 /// <summary>
/// 加載按鈕事件委托
/// </summary>
private void InitializeEvent()
{
ControlTemplate baseWindowTemplate = (ControlTemplate)App.Current.Resources["CustomWindowControlTemplate"];

Button minBtn = (Button)baseWindowTemplate.FindName("btnMin", this);
minBtn.Click += delegate
{
this.WindowState = WindowState.Minimized;
};

Button maxBtn = (Button)baseWindowTemplate.FindName("btnMax", this);
maxBtn.Click += delegate
{
this.WindowState = (this.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal);
};

Button closeBtn = (Button)baseWindowTemplate.FindName("btnClose", this);
closeBtn.Click += delegate
{
this.Close();
};

Border tp = (Border)baseWindowTemplate.FindName("topborder", this);

tp.MouseLeftButtonDown += delegate
{
this.DragMove();
};
}

僅僅這樣實現的話還不夠,因為窗體最大化後會覆蓋任務欄,這是我們不希望看到的,所以還必須通過WINDOW API的窗口句柄來定義最大化後的尺寸

技術分享圖片代碼 /// <summary>
/// 重繪窗體大小
/// </summary>
void win_SourceInitialized(object sender, EventArgs e)
{
System.IntPtr handle = (new WinInterop.WindowInteropHelper(this)).Handle;
WinInterop.HwndSource.FromHwnd(handle).AddHook(new WinInterop.HwndSourceHook(WindowProc));
}
...
[DllImport("user32")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);

[DllImport("User32")]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
...
private static System.IntPtr WindowProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)
{
switch (msg)
{
case 0x0024:
WmGetMinMaxInfo(hwnd, lParam);
handled = true;
break;
}
return (System.IntPtr)0;
}

最後是實現用鼠標拖拽改變窗體大小

然後在Windows1這個CustomWindow類的實例中繪制左右及底部5個拖拽熱區(矩形)

技術分享圖片

最後在Window1.xaml.cs中添加事件委托即可

技術分享圖片代碼 /// <summary>
/// 加載Resize委托
/// </summary>
public void InitializeResizeHandle()
{
WindowResizer wr = new WindowResizer(this);
wr.addResizerRight(right);
wr.addResizerLeft(left);
wr.addResizerDown(bottom);
wr.addResizerLeftDown(leftbottom);
wr.addResizerRightDown(rightbottom);
//wr.addResizerUp(topSizeGrip);
//wr.addResizerLeftUp(topLeftSizeGrip);
//wr.addResizerRightUp(topRightSizeGrip);
}

大功告成了!

技術分享圖片

WPF設計の自定義窗體