当我第一次运行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. 今日头条高级后端开发实习生三轮技术面+HR面 面经

    二面结束后已经意识模糊,好多问过的东西都忘了,而且有一些基础知识就不在这写了,大部分公司都问的差不多... 一面(2018/03/27,11:00~11:50) 1:自我介绍 2:简单说说你这个项目吧 ...

  2. 【CF 453A】 A. Little Pony and Expected Maximum(期望、快速幂)

    A. Little Pony and Expected Maximum time limit per test 1 second memory limit per test 256 megabytes ...

  3. 使用BasicDataSource引发的数据库连接中断的问题和解决方法

    http://blog.csdn.net/itbasketplayer/article/details/44198963 http://blog.sina.com.cn/s/blog_9e3e5499 ...

  4. BZOJ 4197 NOI 2015 寿司晚宴 状压DP

    4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 694  Solved: 440[Submit][Status] ...

  5. 计算机二级软件VC++6.0下载地址

    计算机二级软件VC++6.0介绍: 适合所有参加全国计算机等级考试的童鞋们……见图如下: 下载地址:(以下两者任选其一即可) (1).计算机二级软件VC++6.0(16.35MB) (2).计算机二级 ...

  6. Idea详细配置

    https://blog.csdn.net/m_m254282520/article/details/78900238

  7. GIT(3)----问题汇总

    1.git pull出现的合并问题: Please enter a commit message to explain why this merge is necessary,especially i ...

  8. spring对事务支持的三种形式

    spring对事务支持的三种形式: 1.通过spring配置文件进行切面配置 <bean id="***Manager" class="org.springfram ...

  9. C++ Primer 学习笔记_34_STL实践与分析(8) --引言、pair类型、关联容器

    STL实践与分析 --引言.pair类型.关联容器 引言:     关联容器与顺序容器的本质差别在于:关联容器通过键[key]来存储和读取元素,而顺序容器则通过元素在容器中的位置顺序的存取元素. ma ...

  10. HowTo: Restart SSH Service under Linux / UNIX

    How do I restart SSH service under Linux or UNIX operating systems? The command to restart ssh are a ...