原文: WPF實用指南一:在WPF窗體的邊框中添加搜尋框和按鈕
在邊框中加入一些元素,在應用程式的界面設計中,已經開始流行起來。特别是在浏覽器(Crome,IE,Firefox,Opera)中都有應用。
在WPF中,如何實作這種效果呢?這正是我們今天需要探讨的問題。先看看實作效果
圖一:實作之前的效果圖二:實作之後的效果
這樣的效果依賴于作業系統Aero風格的支援,也就是說在Windows Vista,Windows 7 或者更高版本中可以獲得此中效果。如果要在Windows XP中實作,那麼您就需要另外想辦法了。
好了。我們來看看是怎麼實作的吧。
首先:在MainWindow窗體的xaml代碼中加入以下代碼,這一步沒有什麼特别的,和平常做的一樣。
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
<TextBox Width="150" VerticalAlignment="Center" Text="輸入關鍵詞" />
<Button Content="查找" VerticalAlignment="Center" Margin="5,0,5,0" />
</StackPanel>
<Grid Background="White" Grid.Row="1">
<Label Content="Hello World"></Label>
</Grid>
然後:為窗體設定背景。這一步比較重要,要實作上面圖檔的效果,需要将其設定為Transparent
Background="Transparent"
好了,到此xaml的編輯已經結束了,接下來看看背景代碼是如何實作的。
如果你建立的是WPF的應用程式,隻需要添加System.Drawing引用即可。
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Interop;
using System.Runtime.InteropServices;
要實作上述效果,需要使用一個Win32函數
DwmExtendFrameIntoClientArea這個函數需要個
MARGINS的結構體。代碼定義如下
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cxTopHeight;
public int cxBottomHeight;
}
[DllImport("dwmapi.dll")]
public static extern int DwmExtendFrameIntoClientArea(
IntPtr hWnd, ref MARGINS pMarInset);
Windows
API使用句柄控制着窗體,是以在窗體的Load事件中,第一步我們需要擷取窗體的句柄,使用.NET類庫提供的
WindowInteropHelper類來擷取。
然後從句柄中獲得
HwndSource,它用來宿主WPF的内容。接下來建立MARGINS結構體執行個體用來存儲相關設定。最後調用API。看看代碼實作:
void OnLoaded(object sender, RoutedEventArgs e)
{
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
HwndSource window = HwndSource.FromHwnd(windowHandle);
window.CompositionTarget.BackgroundColor = Colors.Transparent;
MARGINS margins = new MARGINS();
margins.cxTopHeight = 30;
margins = AdjustForDPISettings(margins, windowHandle);
int result = DwmExtendFrameIntoClientArea(windowHandle, ref margins);
}
private MARGINS AdjustForDPISettings(MARGINS input, IntPtr hWnd)
{
MARGINS adjusted = new MARGINS();
var graphics = System.Drawing.Graphics.FromHwnd(hWnd);
float dpiRatioX = graphics.DpiX / 96;
float dpiRatioY = graphics.DpiY / 96;
adjusted.cxLeftWidth = (int)(input.cxLeftWidth * dpiRatioX);
adjusted.cxRightWidth = (int)(input.cxRightWidth * dpiRatioX);
adjusted.cxTopHeight = (int)(input.cxTopHeight * dpiRatioY);
adjusted.cxBottomHeight = (int)(input.cxBottomHeight * dpiRatioY);
return adjusted;
}
到此,整個效果就都實作了。完整代碼如下:
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace WpfTutorial
{
/// <summary>
/// MainWindow.xaml 的互動邏輯
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
void OnLoaded(object sender, RoutedEventArgs e)
{
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
HwndSource window = HwndSource.FromHwnd(windowHandle);
window.CompositionTarget.BackgroundColor = Colors.Transparent;
MARGINS margins = new MARGINS();
margins.cxTopHeight = 30;
margins = AdjustForDPISettings(margins, windowHandle);
int result = DwmExtendFrameIntoClientArea(windowHandle, ref margins);
}
private MARGINS AdjustForDPISettings(MARGINS input, IntPtr hWnd)
{
MARGINS adjusted = new MARGINS();
var graphics = System.Drawing.Graphics.FromHwnd(hWnd);
float dpiRatioX = graphics.DpiX / 96;
float dpiRatioY = graphics.DpiY / 96;
adjusted.cxLeftWidth = (int)(input.cxLeftWidth * dpiRatioX);
adjusted.cxRightWidth = (int)(input.cxRightWidth * dpiRatioX);
adjusted.cxTopHeight = (int)(input.cxTopHeight * dpiRatioY);
adjusted.cxBottomHeight = (int)(input.cxBottomHeight * dpiRatioY);
return adjusted;
}
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cxTopHeight;
public int cxBottomHeight;
}
[DllImport("dwmapi.dll")]
public static extern int DwmExtendFrameIntoClientArea(
IntPtr hWnd, ref MARGINS pMarInset);
}
}