原文:WPF换肤之四:界面设计和代码设计分离
说起WPF来,除了总所周知的图形处理核心的变化外,和Winform比起来,还有一个巨大的变革,那就是真正意义上做到了界面设计和代码设计的分离。这样可以让美工和程序分开进行,而不是糅合在一块,这样做的好处当然也是显而易见的:提高了开发效率。
原先的设计方式
在我们之前设计的代码中,每当添加一个新的窗体的时候,我总是会在这个新的窗体的XAML文件中加入如下的代码,以便使样式能够应用上去:
View Code
<Window x:Class="WpfApplication1.MsgWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="TestWindow" Height="391" Width="418" WindowStyle="None" AllowsTransparency="True" Background="Transparent" OpacityMask="White" ResizeMode="NoResize" PreviewMouseMove="ResetCursor" WindowStartupLocation="CenterScreen"> <Grid Background="Transparent"> <Border BorderThickness="5" BorderBrush="DarkGreen" CornerRadius="10,10,10,10" MouseMove="DisplayResizeCursor" PreviewMouseDown="Resize" Name="top"> <Border.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#eee"/> </LinearGradientBrush> </Border.Background> <Grid> <!--这里放置UIElement.--> </Grid> </Border> </Grid> </Window>
然后,在后台中,为了使窗体能够在最大化时不遮蔽任务栏,拖拉窗体边缘能够改变窗口大小,点按窗体可以实现拖拉的时候,在后台加入了如下的代码:
View Code
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Windows.Interop; using System.Diagnostics; using System.Runtime.InteropServices; namespace WpfApplication1 { /// <summary> /// Interaction logic for TestWindow.xaml /// </summary> public partial class MsgWindow : Window { private const int WM_SYSCOMMAND = 0x112; private HwndSource hs; IntPtr retInt = IntPtr.Zero; public MsgWindow() { InitializeComponent(); this.SourceInitialized += new EventHandler(WSInitialized); } void WSInitialized(object sender, EventArgs e) { hs = PresentationSource.FromVisual(this) as HwndSource; hs.AddHook(new HwndSourceHook(WndProc)); } public double relativeClip = 10; public enum ResizeDirection { Left = 1, Right = 2, Top = 3, TopLeft = 4, TopRight = 5, Bottom = 6, BottomLeft = 7, BottomRight = 8, } [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private void ResizeWindow(ResizeDirection direction) { SendMessage(hs.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero); } private void ResetCursor(object sender, MouseEventArgs e) { if (Mouse.LeftButton != MouseButtonState.Pressed) { this.Cursor = Cursors.Arrow; } } private void Resize(object sender, MouseButtonEventArgs e) { Border clickedBorder = sender as Border; Point pos = Mouse.GetPosition(this); double x = pos.X; double y = pos.Y; double w = this.ActualWidth; double h = this.ActualHeight; if (x <= relativeClip & y <= relativeClip) // left top { this.Cursor = Cursors.SizeNWSE; ResizeWindow(ResizeDirection.TopLeft); } if (x >= w - relativeClip & y <= relativeClip) //right top { this.Cursor = Cursors.SizeNESW; ResizeWindow(ResizeDirection.TopRight); } if (x >= w - relativeClip & y >= h - relativeClip) //bottom right { this.Cursor = Cursors.SizeNWSE; ResizeWindow(ResizeDirection.BottomRight); } if (x <= relativeClip & y >= h - relativeClip) // bottom left { this.Cursor = Cursors.SizeNESW; ResizeWindow(ResizeDirection.BottomLeft); } if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top { this.Cursor = Cursors.SizeNS; ResizeWindow(ResizeDirection.Top); } if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right { this.Cursor = Cursors.SizeWE; ResizeWindow(ResizeDirection.Right); } if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom { this.Cursor = Cursors.SizeNS; ResizeWindow(ResizeDirection.Bottom); } if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left { this.Cursor = Cursors.SizeWE; ResizeWindow(ResizeDirection.Left); } } private void DisplayResizeCursor(object sender, MouseEventArgs e) { Border clickBorder = sender as Border; Point pos = Mouse.GetPosition(this); double x = pos.X; double y = pos.Y; double w= this.ActualWidth; double h= this.ActualHeight; this.label1.Content = x + "--" + y; if (x <= relativeClip & y <= relativeClip) // left top { this.Cursor = Cursors.SizeNWSE; } if (x >= w - relativeClip & y <= relativeClip) //right top { this.Cursor = Cursors.SizeNESW; } if (x >= w - relativeClip & y >= h - relativeClip) //bottom right { this.Cursor = Cursors.SizeNWSE; } if (x <= relativeClip & y >= h - relativeClip) // bottom left { this.Cursor = Cursors.SizeNESW; } if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top { this.Cursor = Cursors.SizeNS; } if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right { this.Cursor = Cursors.SizeWE; } if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom { this.Cursor = Cursors.SizeNS; } if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left { this.Cursor = Cursors.SizeWE; } } private void button1_Click(object sender, RoutedEventArgs e) { this.WindowState = (this.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal); } #region 这一部分用于最大化时不遮蔽任务栏 private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) { MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); // Adjust the maximized size and position to fit the work area of the correct monitor int MONITOR_DEFAULTTONEAREST = 0x00000002; System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); if (monitor != System.IntPtr.Zero) { MONITORINFO monitorInfo = new MONITORINFO(); GetMonitorInfo(monitor, monitorInfo); RECT rcWorkArea = monitorInfo.rcWork; RECT rcMonitorArea = monitorInfo.rcMonitor; mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left); mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top); mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left); mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top); } Marshal.StructureToPtr(mmi, lParam, true); } /// <summary> /// POINT aka POINTAPI /// </summary> [StructLayout(LayoutKind.Sequential)] public struct POINT { /// <summary> /// x coordinate of point. /// </summary> public int x; /// <summary> /// y coordinate of point. /// </summary> public int y; /// <summary> /// Construct a point of coordinates (x,y). /// </summary> public POINT(int x, int y) { this.x = x; this.y = y; } } /// <summary> /// 窗体大小信息 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct MINMAXINFO { public POINT ptReserved; public POINT ptMaxSize; public POINT ptMaxPosition; public POINT ptMinTrackSize; public POINT ptMaxTrackSize; }; /// <summary> Win32 </summary> [StructLayout(LayoutKind.Sequential, Pack = 0)] public struct RECT { /// <summary> Win32 </summary> public int left; /// <summary> Win32 </summary> public int top; /// <summary> Win32 </summary> public int right; /// <summary> Win32 </summary> public int bottom; /// <summary> Win32 </summary> public static readonly RECT Empty = new RECT(); /// <summary> Win32 </summary> public int Width { get { return Math.Abs(right - left); } // Abs needed for BIDI OS } /// <summary> Win32 </summary> public int Height { get { return bottom - top; } } /// <summary> Win32 </summary> public RECT(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } /// <summary> Win32 </summary> public RECT(RECT rcSrc) { this.left = rcSrc.left; this.top = rcSrc.top; this.right = rcSrc.right; this.bottom = rcSrc.bottom; } /// <summary> Win32 </summary> public bool IsEmpty { get { // BUGBUG : On Bidi OS (hebrew arabic) left > right return left >= right || top >= bottom; } } /// <summary> Return a user friendly representation of this struct </summary> public override string ToString() { if (this == RECT.Empty) { return "RECT {Empty}"; } return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }"; } /// <summary> Determine if 2 RECT are equal (deep compare) </summary> public override bool Equals(object obj) { if (!(obj is Rect)) { return false; } return (this == (RECT)obj); } /// <summary>Return the HashCode for this struct (not garanteed to be unique)</summary> public override int GetHashCode() { return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode(); } /// <summary> Determine if 2 RECT are equal (deep compare)</summary> public static bool operator ==(RECT rect1, RECT rect2) { return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom); } /// <summary> Determine if 2 RECT are different(deep compare)</summary> public static bool operator !=(RECT rect1, RECT rect2) { return !(rect1 == rect2); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class MONITORINFO { /// <summary> /// </summary> public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); /// <summary> /// </summary> public RECT rcMonitor = new RECT(); /// <summary> /// </summary> public RECT rcWork = new RECT(); /// <summary> /// </summary> public int dwFlags = 0; } [DllImport("user32")] internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); [DllImport("User32")] internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); #endregion private void MyMacClass_SourceInitialized(object sender, EventArgs e) { hs = PresentationSource.FromVisual((Visual)sender) as HwndSource; hs.AddHook(new HwndSourceHook(WndProc)); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case 0x0024:/* WM_GETMINMAXINFO */ WmGetMinMaxInfo(hwnd, lParam); handled = true; break; default: break; } return (System.IntPtr)0; } } }
如果按照上面的设计,那么每加入一个新的窗体,都要重复上面的两个步骤的话,加入一个工程中需要加入的新窗体特别多,估计这种操作足以让一个正常人疯掉了。并且假如以后border的颜色要修改,那得修改多少页面啊~~~
改进的设计方式
所以,为了便于设计和维护,实现所谓的UI和代码分析,让我们提出一个假设的方案来:
首先,所有的公共样式放到一个样式文件中,所有新加的窗体都能共享这个公共的样式文件。
其次,所有的公共事件(窗体最大化,最小化,关闭等),都放到一个公共的基类中,所有新加的窗体只要继承该基类,即可继承系统公用的事件操作。
那么,本着这个假设,我们开始来进行。
首先,对于公共样式,我们需要添加一个“资源词典”的页面,用来设计公共样式:
添加完成后,会看到如下XAML:
View Code
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> </ResourceDictionary>
下面我们在这个文件中添加样式:
View Code
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MyOwnerDrawnWindow.Resource_Dictionaries.MyTheme" > <!-- Border defining the frame of the Window --> <Style x:Key="MywindowBorder" TargetType="Border"> <Setter Property="CornerRadius" Value="10, 10, 10, 10" /> <Setter Property="BorderBrush" Value="DarkGreen"></Setter> <Setter Property="BorderThickness" Value="5" /> <Setter Property="HorizontalAlignment" Value="Stretch"></Setter> <Setter Property="VerticalAlignment" Value="Stretch"></Setter> <Setter Property="Background" Value="#ababab"></Setter> </Style> <ControlTemplate x:Key="MyWindowTemplate" TargetType="{x:Type Window}"> <Grid> <Border x:Name="MyBorder" Style="{StaticResource MywindowBorder}" > <Border.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#eee"/> </LinearGradientBrush> </Border.Background> <!--这一句很重要,主要用于放置界面元素,和asp.net中的masterpage有点像--> <AdornerDecorator> <ContentPresenter /> </AdornerDecorator> </Border> </Grid> </ControlTemplate> <!-- My Window Style --> <Style x:Key="MyWindowStyle" TargetType="Window"> <Setter Property="Background" Value="Transparent" /> <Setter Property="WindowStyle" Value="None" /> <Setter Property="AllowsTransparency" Value="True" /> <Setter Property="Template" Value="{StaticResource MyWindowTemplate}" /> </Style> </ResourceDictionary>
好了,这就是我们的样式文件,接下来我们需要处理这个样式中的Border事件,让其支持鼠标左键拖拉功能。
新建一个类,命名为MyThemeClass.cs,让其继承自Window基类。在MyThemeClass类中,我们主要处理两个内容,一个是支持鼠标左键拖拉以便改变窗体大小,另一个是使窗体不遮蔽任务栏。
具体代码如下:
View Code
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Media; using System.Windows.Interop; using System.Runtime.InteropServices; using System.Windows.Controls; using System.Windows.Input; namespace MyOwnerDrawnWindow { public class MyThemeClass:Window { private const int WM_SYSCOMMAND = 0x112; public const int WM_LBUTTONUP = 0x0202; private HwndSource hs; IntPtr retInt = IntPtr.Zero; public double relativeClip = 10; public MyThemeClass() { this.Loaded += delegate { InitializeEvent(); }; this.SourceInitialized +=new EventHandler(MyMacClass_SourceInitialized); } private void MyMacClass_SourceInitialized(object sender, EventArgs e) { hs = PresentationSource.FromVisual((Visual)sender) as HwndSource; hs.AddHook(new HwndSourceHook(WndProc)); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case 0x0024:/* WM_GETMINMAXINFO */ WmGetMinMaxInfo(hwnd, lParam); handled = true; break; default: break; } return (System.IntPtr)0; } #region 这一部分用于最大化时不遮蔽任务栏 private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) { MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); // Adjust the maximized size and position to fit the work area of the correct monitor int MONITOR_DEFAULTTONEAREST = 0x00000002; System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); if (monitor != System.IntPtr.Zero) { MONITORINFO monitorInfo = new MONITORINFO(); GetMonitorInfo(monitor, monitorInfo); RECT rcWorkArea = monitorInfo.rcWork; RECT rcMonitorArea = monitorInfo.rcMonitor; mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left); mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top); mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left); mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top); } Marshal.StructureToPtr(mmi, lParam, true); } /// <summary> /// POINT aka POINTAPI /// </summary> [StructLayout(LayoutKind.Sequential)] public struct POINT { /// <summary> /// x coordinate of point. /// </summary> public int x; /// <summary> /// y coordinate of point. /// </summary> public int y; /// <summary> /// Construct a point of coordinates (x,y). /// </summary> public POINT(int x, int y) { this.x = x; this.y = y; } } [StructLayout(LayoutKind.Sequential)] public struct MINMAXINFO { public POINT ptReserved; public POINT ptMaxSize; public POINT ptMaxPosition; public POINT ptMinTrackSize; public POINT ptMaxTrackSize; }; [StructLayout(LayoutKind.Sequential, Pack = 0)] public struct RECT { /// <summary> Win32 </summary> public int left; /// <summary> Win32 </summary> public int top; /// <summary> Win32 </summary> public int right; /// <summary> Win32 </summary> public int bottom; /// <summary> Win32 </summary> public static readonly RECT Empty = new RECT(); /// <summary> Win32 </summary> public int Width { get { return Math.Abs(right - left); } // Abs needed for BIDI OS } /// <summary> Win32 </summary> public int Height { get { return bottom - top; } } /// <summary> Win32 </summary> public RECT(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } /// <summary> Win32 </summary> public RECT(RECT rcSrc) { this.left = rcSrc.left; this.top = rcSrc.top; this.right = rcSrc.right; this.bottom = rcSrc.bottom; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class MONITORINFO { /// <summary> /// </summary> public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); /// <summary> /// </summary> public RECT rcMonitor = new RECT(); /// <summary> /// </summary> public RECT rcWork = new RECT(); /// <summary> /// </summary> public int dwFlags = 0; } [DllImport("user32")] internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); [DllImport("User32")] internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); #endregion #region 这一部分是四个边加上四个角 public enum ResizeDirection { Left = 1, Right = 2, Top = 3, TopLeft = 4, TopRight = 5, Bottom = 6, BottomLeft = 7, BottomRight = 8, } #endregion #region 用于改变窗体大小 [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private void ResizeWindow(ResizeDirection direction) { SendMessage(hs.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero); } #endregion #region 为元素注册事件 private void InitializeEvent() { ControlTemplate baseWindowTemplate = (ControlTemplate)App.Current.Resources["MyWindowTemplate"]; Border borderClip = (Border)baseWindowTemplate.FindName("MyBorder", this); borderClip.MouseMove += delegate { DisplayResizeCursor(null,null); }; borderClip.PreviewMouseDown += delegate { Resize(null,null); }; borderClip.MouseLeftButtonDown += delegate { DragMove(); }; this.PreviewMouseMove += delegate { ResetCursor(null,null); }; } #endregion #region 重写的DragMove,以便解决利用系统自带的DragMove出现Exception的情况 public new void DragMove() { if (this.WindowState == WindowState.Normal) { SendMessage(hs.Handle, WM_SYSCOMMAND, (IntPtr)0xf012, IntPtr.Zero); SendMessage(hs.Handle, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero); } } #endregion #region 显示拖拉鼠标形状 private void DisplayResizeCursor(object sender, MouseEventArgs e) { Point pos = Mouse.GetPosition(this); double x = pos.X; double y = pos.Y; double w = this.ActualWidth; //注意这个地方使用ActualWidth,才能够实时显示宽度变化 double h = this.ActualHeight; if (x <= relativeClip & y <= relativeClip) // left top { this.Cursor = Cursors.SizeNWSE; } if (x >= w - relativeClip & y <= relativeClip) //right top { this.Cursor = Cursors.SizeNESW; } if (x >= w - relativeClip & y >= h - relativeClip) //bottom right { this.Cursor = Cursors.SizeNWSE; } if (x <= relativeClip & y >= h - relativeClip) // bottom left { this.Cursor = Cursors.SizeNESW; } if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top { this.Cursor = Cursors.SizeNS; } if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right { this.Cursor = Cursors.SizeWE; } if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom { this.Cursor = Cursors.SizeNS; } if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left { this.Cursor = Cursors.SizeWE; } } #endregion #region 还原鼠标形状 private void ResetCursor(object sender, MouseEventArgs e) { if (Mouse.LeftButton != MouseButtonState.Pressed) { this.Cursor = Cursors.Arrow; } } #endregion #region 判断区域,改变窗体大小 private void Resize(object sender, MouseButtonEventArgs e) { Point pos = Mouse.GetPosition(this); double x = pos.X; double y = pos.Y; double w = this.ActualWidth; double h = this.ActualHeight; if (x <= relativeClip & y <= relativeClip) // left top { this.Cursor = Cursors.SizeNWSE; ResizeWindow(ResizeDirection.TopLeft); } if (x >= w - relativeClip & y <= relativeClip) //right top { this.Cursor = Cursors.SizeNESW; ResizeWindow(ResizeDirection.TopRight); } if (x >= w - relativeClip & y >= h - relativeClip) //bottom right { this.Cursor = Cursors.SizeNWSE; ResizeWindow(ResizeDirection.BottomRight); } if (x <= relativeClip & y >= h - relativeClip) // bottom left { this.Cursor = Cursors.SizeNESW; ResizeWindow(ResizeDirection.BottomLeft); } if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top { this.Cursor = Cursors.SizeNS; ResizeWindow(ResizeDirection.Top); } if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right { this.Cursor = Cursors.SizeWE; ResizeWindow(ResizeDirection.Right); } if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom { this.Cursor = Cursors.SizeNS; ResizeWindow(ResizeDirection.Bottom); } if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left { this.Cursor = Cursors.SizeWE; ResizeWindow(ResizeDirection.Left); } } #endregion } }
这样,我们的Theme和类就创建好了,那么,在主窗体中,我们该如何应用上去呢?当然,这个不是难事,并且异常简单:
首先,创建一个新的窗体Window1, 它需要继承自MyThemeClass类:
public partial class Window1 : MyThemeClass
然后再XAML中只需要修改两个地方,首先是添加入一个新的引用:
xmlns:src="clr-namespace:MyOwnerDrawnWindow"
添加完这个引用后,把<Window….></Window>修改成<src:MyThemeClass……></ MyThemeClass> 这样做的目的是防止由于继承基类的不同而造成XAML的识别错误。
最后,只需要添加这句Style="{StaticResource MyWindowStyle}" 就行了。 这样就算是添加完成了新的窗体,每一个新添加的窗体都按照这种方式添加即可,是不是简洁了许多? 并且后期维护也简单多了。
View Code
<src:MyThemeClass x:Class="MyOwnerDrawnWindow.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:src="clr-namespace:MyOwnerDrawnWindow" Title="Window1" Height="335" Width="706" Style="{StaticResource MyWindowStyle}"> <Grid> <!--这里放置你的UIElement--> </Grid> </src:MyThemeClass>
好了,最后一步就是讲Theme文件关联起来,在APP.xaml文件中添加对资源文件的引用即可:
View Code
<Application x:Class="MyOwnerDrawnWindow.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="Window1.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="MyTheme.xaml"></ResourceDictionary> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
这样运行起来以后,达到的预期的效果。
源码下载