当我第一次运行Zune时,我为这些美丽的UI所折服。当时就说这肯定不是用WPF做的,因为这些字体是如此的清晰而且UI反映的也非常快速。。而且我从维基百科上也了解到Zune的第一个版本是2006年发布的,而WPF与.NET 3.0却是 2006 年11月发布的。
那么问题来了,如果它不是WPF做的,那它是用什么技术做到的呢?为了找到答案,我使用Process Explorer工具来看看Zune是如何启动的,默认情况下,.NET应用程序都是被用黄色高亮显示的。
很好,这说明Zune肯定是.net 应用程序了,然后我们可以看到Zune需要如下库

然后用 Reflector一看:
如你所见,根名空间是 Microsoft.Iris. 我在Google上搜到这玩意看上去就像某种原始的WPF组件 -- MCML
WPF能创造出类似的UI吗?
第一个难点就是就是设定WindowStyle为None。因为这有这有才能让标题栏以及边框不可见
那该如何移动窗体呢?
首先添加一个Shape(Rectangle),然后为它订阅PreviewMouseDown事件处理。
02 | if (DateTime.Now.Subtract(m_headerLastClicked) <= s_doubleClick) |
07 | HandleRestoreClick( null , null ); |
10 | m_headerLastClicked = DateTime.Now; |
12 | if (Mouse.LeftButton == MouseButtonState.Pressed) |
该如何任意改变窗体大小?
在主窗体的四个角分别添加一个Shape(比如Rectangle)然后为它们都订阅PreviewMouseDown事件处理:
01 | Rectangle clickedRectangle = (Rectangle)sender; |
03 | switch (clickedRectangle.Name) |
06 | Cursor = Cursors.SizeNS; |
07 | ResizeWindow(ResizeDirection.Top); |
10 | Cursor = Cursors.SizeNS; |
11 | ResizeWindow(ResizeDirection.Bottom); |
下面就是用鼠标重新调整窗体大小的代码
01 | /// <summary> /// Resizes the window. |
02 | /// </summary> /// <param name="direction">The direction. |
03 | private void ResizeWindow(ResizeDirection direction) |
05 | NativeMethods.SendMessage(m_hwndSource.Handle, WM_SYSCOMMAND, |
06 | (IntPtr)(61440 + direction), IntPtr.Zero); |
09 | [DllImport( "user32.dll" , CharSet = CharSet.Auto)] |
10 | internal static extern IntPtr SendMessage( |
如何为窗体添加阴影效果。
实际上有两种做法:
第一种就是试用DWM API。这个方法需要订阅SourceInitialized事件。
01 | /// <summary> /// Raises the <see cref="FrameworkElement.Initialized"> event. |
02 | /// This method is invoked whenever |
03 | /// <see cref="P:FrameworkElement.IsInitialized"> /// is set to true internally. |
04 | /// </see></see></summary> /// <param name="e">The <see cref="T:RoutedEventArgs"> /// that contains the event data. |
05 | protected override void OnInitialized(EventArgs e) |
07 | AllowsTransparency = false ; |
08 | ResizeMode = ResizeMode.NoResize; |
11 | WindowStartupLocation = WindowStartupLocation.CenterScreen; |
12 | WindowStyle = WindowStyle.None; |
14 | SourceInitialized += HandleSourceInitialized; |
16 | base .OnInitialized(e); |
19 | /// <summary> /// Handles the source initialized. |
20 | /// </summary> /// <param name="sender">The sender. |
21 | /// <param name="e">The <see cref="System.EventArgs"> /// instance containing the event data. |
22 | private void HandleSourceInitialized(Object sender, EventArgs e) |
24 | m_hwndSource = (HwndSource)PresentationSource.FromVisual( this ); |
28 | HwndSource.FromHwnd(m_hwndSource.Handle).AddHook( |
29 | new HwndSourceHook(NativeMethods.WindowProc)); |
32 | Int32 DWMWA_NCRENDERING_POLICY = 2; |
33 | NativeMethods.DwmSetWindowAttribute( |
35 | DWMWA_NCRENDERING_POLICY, |
36 | ref DWMWA_NCRENDERING_POLICY, |
40 | NativeMethods.ShowShadowUnderWindow(m_hwndSource.Handle); |
无阴影的窗体
有阴影的窗体
第二种方法就是使用四个外部的透明窗体来制造了阴影的假象,如下图所示
1,用代码的方式创建一个透明的窗体
2,找到Main Window 在屏幕上的坐标,尤其是左上角
3,计算4个透明窗口的坐标
4,当我们移动Main Window时,4个边框透明窗口也需要跟着移动
5,当我们重新设定 Main Window大小时,4个边框透明窗口也要跟着变化大小。
说这么多看上去好像很难,来让我们看看实现的代码吧。
创建透明窗体的代码
01 | /// <summary> /// Initializes the surrounding windows. |
02 | /// </summary> private void InitializeSurrounds() |
05 | m_wndT = CreateTransparentWindow(); |
08 | m_wndL = CreateTransparentWindow(); |
11 | m_wndB = CreateTransparentWindow(); |
14 | m_wndR = CreateTransparentWindow(); |
19 | /// <summary> /// Creates an empty window. |
20 | /// </summary> /// <returns></returns> private static Window CreateTransparentWindow() |
22 | Window wnd = new Window(); |
23 | wnd.AllowsTransparency = true ; |
24 | wnd.ShowInTaskbar = false ; |
25 | wnd.WindowStyle = WindowStyle.None; |
26 | wnd.Background = null ; |
31 | /// <summary> /// Sets the artificial drop shadow. |
32 | /// </summary> /// <param name="active">if set to <c>true</c> [active]. |
33 | private void SetSurroundShadows(Boolean active = true ) |
37 | Double cornerRadius = 1.75; |
39 | m_wndT.Content = GetDecorator( |
40 | "Images/ACTIVESHADOWTOP.PNG" ); |
41 | m_wndL.Content = GetDecorator( |
42 | "Images/ACTIVESHADOWLEFT.PNG" , cornerRadius); |
43 | m_wndB.Content = GetDecorator( |
44 | "Images/ACTIVESHADOWBOTTOM.PNG" ); |
45 | m_wndR.Content = GetDecorator( |
46 | "Images/ACTIVESHADOWRIGHT.PNG" , cornerRadius); |
50 | m_wndT.Content = GetDecorator( |
51 | "Images/INACTIVESHADOWTOP.PNG" ); |
52 | m_wndL.Content = GetDecorator( |
53 | "Images/INACTIVESHADOWLEFT.PNG" ); |
54 | m_wndB.Content = GetDecorator( |
55 | "Images/INACTIVESHADOWBOTTOM.PNG" ); |
56 | m_wndR.Content = GetDecorator( |
57 | "Images/INACTIVESHADOWRIGHT.PNG" ); |
62 | private Decorator GetDecorator(String imageUri, Double radius = 0) |
64 | Border border = new Border(); |
65 | border.CornerRadius = new CornerRadius(radius); |
66 | border.Background = new ImageBrush( |
68 | new Uri(BaseUriHelper.GetBaseUri( this ), |
计算位置高度的代码
01 | /// <summary> /// Raises the <see cref="FrameworkElement.Initialized"> event. |
02 | /// This method is invoked whenever |
03 | /// <see cref="FrameworkElement.IsInitialized"> /// is set to true internally. |
04 | /// </see></see></summary> /// <param name="e">The <see cref="T:RoutedEventArgs"> /// that contains the event data. |
05 | protected override void OnInitialized(EventArgs e) |
09 | LocationChanged += HandleLocationChanged; |
10 | SizeChanged += HandleLocationChanged; |
11 | StateChanged += HandleWndStateChanged; |
13 | InitializeSurrounds(); |
16 | base .OnInitialized(e); |
19 | /// <summary> /// Handles the location changed. |
20 | /// </summary> /// <param name="sender">The sender. |
21 | /// <param name="e">The <see cref="System.EventArgs"> /// instance containing the event data. |
22 | private void HandleLocationChanged(Object sender, EventArgs e) |
24 | m_wndT.Left = Left - c_edgeWndSize; |
25 | m_wndT.Top = Top - m_wndT.Height; |
26 | m_wndT.Width = Width + c_edgeWndSize * 2; |
27 | m_wndT.Height = c_edgeWndSize; |
29 | m_wndL.Left = Left - m_wndL.Width; |
31 | m_wndL.Width = c_edgeWndSize; |
32 | m_wndL.Height = Height; |
34 | m_wndB.Left = Left - c_edgeWndSize; |
35 | m_wndB.Top = Top + Height; |
36 | m_wndB.Width = Width + c_edgeWndSize * 2; |
37 | m_wndB.Height = c_edgeWndSize; |
39 | m_wndR.Left = Left + Width; |
41 | m_wndR.Width = c_edgeWndSize; |
42 | m_wndR.Height = Height; |
45 | /// <summary> /// Handles the windows state changed. |
46 | /// </summary> /// <param name="sender">The sender. |
47 | /// <param name="e">The <see cref="System.EventArgs"> /// instance containing the event data. |
48 | private void HandleWndStateChanged(Object sender, EventArgs e) |
50 | if (WindowState == WindowState.Normal) |
原文链接
,
OSChina.NET原创翻译