当我第一次运行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事件处理。
01 // Is this a double-click?
02 if (DateTime.Now.Subtract(m_headerLastClicked) <= s_doubleClick)
03 {
04   // Execute the code inside the event handler for the
05   // restore button click passing null for the sender
06   // and null for the event args.
07   HandleRestoreClick(nullnull);
08 }
09  
10 m_headerLastClicked = DateTime.Now;
11  
12 if (Mouse.LeftButton == MouseButtonState.Pressed)
13 {
14   DragMove();
15 }
该如何任意改变窗体大小?
在主窗体的四个角分别添加一个Shape(比如Rectangle)然后为它们都订阅PreviewMouseDown事件处理:
01 Rectangle clickedRectangle = (Rectangle)sender;
02     
03 switch (clickedRectangle.Name)
04 {
05   case "top":
06       Cursor = Cursors.SizeNS;
07       ResizeWindow(ResizeDirection.Top);
08       break;
09   case "bottom":
10       Cursor = Cursors.SizeNS;
11       ResizeWindow(ResizeDirection.Bottom);
12       break;
13   // ...
14 }
 
下面就是用鼠标重新调整窗体大小的代码
01 /// <summary> /// Resizes the window.
02 /// </summary> /// <param name="direction">The direction.
03 private void ResizeWindow(ResizeDirection direction)
04 {
05   NativeMethods.SendMessage(m_hwndSource.Handle, WM_SYSCOMMAND,
06       (IntPtr)(61440 + direction), IntPtr.Zero);
07 }
08  
09 [DllImport("user32.dll", CharSet = CharSet.Auto)]
10 internal static extern IntPtr SendMessage(
11   IntPtr hWnd,
12   UInt32 msg,
13   IntPtr wParam,
14   IntPtr lParam);
如何为窗体添加阴影效果。
实际上有两种做法:
第一种就是试用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)
06 {
07   AllowsTransparency    = false;
08   ResizeMode            = ResizeMode.NoResize;
09   Height                = 480;
10   Width                 = 852;
11   WindowStartupLocation = WindowStartupLocation.CenterScreen;
12   WindowStyle           = WindowStyle.None;
13  
14   SourceInitialized    += HandleSourceInitialized;
15  
16   base.OnInitialized(e);
17 }
18     
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)
23 {
24   m_hwndSource = (HwndSource)PresentationSource.FromVisual(this);
25  
26   // Returns the HwndSource object for the window
27   // which presents WPF content in a Win32 window.
28   HwndSource.FromHwnd(m_hwndSource.Handle).AddHook(
29       new HwndSourceHook(NativeMethods.WindowProc));
30  
31   // http://msdn.microsoft.com/en-us/library/aa969524(VS.85).aspx
32   Int32 DWMWA_NCRENDERING_POLICY = 2;
33   NativeMethods.DwmSetWindowAttribute(
34       m_hwndSource.Handle,
35       DWMWA_NCRENDERING_POLICY,
36       ref DWMWA_NCRENDERING_POLICY,
37       4);
38  
39   // http://msdn.microsoft.com/en-us/library/aa969512(VS.85).aspx
40   NativeMethods.ShowShadowUnderWindow(m_hwndSource.Handle);
41 }</see></see>

无阴影的窗体

有阴影的窗体
 
 
 
第二种方法就是使用四个外部的透明窗体来制造了阴影的假象,如下图所示
 
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()
03 {
04   // Top.
05   m_wndT = CreateTransparentWindow();
06  
07   // Left.
08   m_wndL = CreateTransparentWindow();
09  
10   // Bottom.
11   m_wndB = CreateTransparentWindow();
12  
13   // Right.
14   m_wndR = CreateTransparentWindow();
15  
16   SetSurroundShadows();
17 }
18     
19 /// <summary> /// Creates an empty window.
20 /// </summary> /// <returns></returns> private static Window CreateTransparentWindow()
21 {
22   Window wnd             = new Window();
23   wnd.AllowsTransparency = true;
24   wnd.ShowInTaskbar      = false;
25   wnd.WindowStyle        = WindowStyle.None;
26   wnd.Background         = null;
27  
28   return wnd;
29 }
30  
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)
34 {
35   if (active)
36   {
37       Double cornerRadius = 1.75;
38  
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);
47   }
48   else
49   {
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");
58   }
59 }
60  
61 [DebuggerStepThrough]
62 private Decorator GetDecorator(String imageUri, Double radius = 0)
63 {
64   Border border       = new Border();
65   border.CornerRadius = new CornerRadius(radius);
66   border.Background   = new ImageBrush(
67       new BitmapImage(
68           new Uri(BaseUriHelper.GetBaseUri(this),
69               imageUri)));
70  
71   return border;
72 }
 
计算位置高度的代码

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)
06 {
07   // ...
08  
09   LocationChanged += HandleLocationChanged;
10   SizeChanged     += HandleLocationChanged;
11   StateChanged    += HandleWndStateChanged;
12  
13   InitializeSurrounds();
14   ShowSurrounds();
15  
16   base.OnInitialized(e);
17 }
18     
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)
23 {
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;
28  
29   m_wndL.Left   = Left - m_wndL.Width;
30   m_wndL.Top    = Top;
31   m_wndL.Width  = c_edgeWndSize;
32   m_wndL.Height = Height;
33  
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;
38  
39   m_wndR.Left   = Left + Width;
40   m_wndR.Top    = Top;
41   m_wndR.Width  = c_edgeWndSize;
42   m_wndR.Height = Height;
43 }
44     
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)
49 {
50   if (WindowState == WindowState.Normal)
51   {
52       ShowSurrounds();
53   }
54   else
55   {
56       HideSurrounds();
57   }
58 }</see></see></see>

原文链接 , OSChina.NET原创翻译

使用WPF来创建 Metro UI的更多相关文章

  1. 使用WPF来创建 Metro UI程序

    本文转载:http://www.cnblogs.com/TianFang/p/3184211.html 这个是我以前网上看到的一篇文章,原文地址是:Building a Metro UI with W ...

  2. WPF 使用MahApps.Metro UI库

    在WPF中要想使用Metro风格是很简单的,可以自己画嘛.. 但是为了节省时间,哈,今天给大家推荐一款国外Metro风格的控件库. 本文只起到抛砖引玉的作用,有兴趣还是推荐大家上官网,Thanks,官 ...

  3. 收集Windows 8 Metro UI 风格网站资源,觉得不错的顶啊!!

    这些资源包含:模板,框架,jQuery插件,图标集等.帮助你快速开发Windows 8 Metro UI风格的网站.本文转自虾米站长网 Frameworks & Templates For M ...

  4. 7 款免费的 Metro UI 模板

    #1 – Free Metro Ui Style template by Asif Aleem 很棒的蓝色调 Metro UI 管理模板 #2: Metro-Bootstrap by TalksLab ...

  5. 【今日推荐】10大流行的 Metro UI 风格的 Bootstrap 主题和模板

    1. BootMetro 基于 Twitter Bootstrap 的简单灵活的 HTML.CSS 和 Javascript 框架,Win8 风格,大爱啊! 立即下载     效果演示 2. Boot ...

  6. 为WPF项目创建单元测试

    原文作者: 周银辉  来源: 博客园 原文地址:http://www.cnblogs.com/zhouyinhui/archive/2007/09/30/911522.html 可能你已发现一个问题, ...

  7. WPF 跨应用程序域的 UI(Cross AppDomain UI)

    为自己写的程序添加插件真的是一个相当常见的功能,然而如果只是简单加载程序集然后去执行程序集中的代码,会让宿主应用程序暴露在非常危险的境地!因为只要插件能够运行任何一行代码,就能将宿主应用程序修改得天翻 ...

  8. WPF 支持的多线程 UI 并不是线程安全的

    原文:WPF 支持的多线程 UI 并不是线程安全的 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可.欢迎转载.使用.重新发布,但务必保留文章署名吕毅(包含链 ...

  9. Bootstrap看厌了?试试Metro UI CSS吧

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:Bootstrap作为一款超级流行的前端框架,已经成为很多人的首选,不过有时未免有点审 ...

随机推荐

  1. Onenet学习笔记

    中国移动物联网开放平台:https://open.iot.10086.cn/ 一.平台概述 简介 OneNET是中国移动物联网有限公司响应“大众创新.万众创业”以及基于开放共赢的理念,面向公共服务自主 ...

  2. #pragma region、{}

    定义一个region,这个region内部的代码你可以把它折叠起来是用于组织代码的,没有其他特别重要的意义. 而{}定义了作用域 { int a = 0; } { int a = 0; }

  3. BZOJ 4726 POI 2017 Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  4. UVALive 5058 Counting BST 数学

    B - Counting BST Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit S ...

  5. cocos2dx 字符串拼接

    ;i<;i++){ ]; sprintf(str,"%d",i); ]; strcpy(totalFilename, "game_loading") ; ...

  6. 【原】使用Spring自带的JdbcTemplate。

    使用Spring自带的JdbcTemplate,可以简化对数据库的操作,用起来十分方便.通过一下几个步骤的配置,即可以使用JdbcTemplate. (1)配置好Spring的数据源,加入mysql驱 ...

  7. ThinkPHP 数据库操作之数据表模型和基础模型 ( Model )

    一.定义数据表模型 1.模型映射 要测试数据库是否正常连接,最直接的办法就是在当前控制器中实例化数据表,然后使用 dump 函数输出,查看数据库的链接状态.代码: public function te ...

  8. mac 下 outlook 邮箱 服务器端口设置

  9. Android 手动按power键上锁,没有锁屏提示音,无法恢复【单机必现】

    測试步骤 [測试版本号]T0606 [模块版本号] NAVI锁屏:5.0.0.ck [測试步骤] 1.手动按power键上锁, [測试结果] 没有锁屏提示音,无法恢复[单机必现] [预期结果] 有提示 ...

  10. Java 8 的新特性和改进总览

    这篇文章是对Java 8中即将到来的改进做一个面向开发者的综合性的总结,JDK的这一特性将会在2013年9月份发布. 在写这篇文章的时候,Java 8的开发工作仍然在紧张有序的进行中,语言特新和API ...