• 使用WPF来创建 Metro UI


    当我第一次运行Zune时,我为这些美丽的UI所折服。当时就说这肯定不是用WPF做的,因为这些字体是如此的清晰而且UI反映的也非常快速。。而且我从维基百科上也了解到Zune的第一个版本是2006年发布的,而WPF与.NET 3.0却是 2006 年11月发布的。

     
    那么问题来了,如果它不是WPF做的,那它是用什么技术做到的呢?为了找到答案,我使用Process Explorer工具来看看Zune是如何启动的,默认情况下,.NET应用程序都是被用黄色高亮显示的。
    使用WPF来创建 Metro UI
     

    很好,这说明Zune肯定是.net 应用程序了,然后我们可以看到Zune需要如下库
    使用WPF来创建 Metro UI

    然后用 Reflector一看:
     
    如你所见,根名空间是 Microsoft.Iris. 我在Google上搜到这玩意看上去就像某种原始的WPF组件 -- MCML
     
    WPF能创造出类似的UI吗?
    第一个难点就是就是设定WindowStyle为None。因为这有这有才能让标题栏以及边框不可见
    使用WPF来创建 Metro UI
     
    那该如何移动窗体呢?
    首先添加一个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>
    无阴影的窗体
    使用WPF来创建 Metro UI
    有阴影的窗体
    使用WPF来创建 Metro UI 
     
     
    第二种方法就是使用四个外部的透明窗体来制造了阴影的假象,如下图所示
    使用WPF来创建 Metro UI
     
    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原创翻译
  • 相关阅读:
    ASP.Net MVC的一个开源框架
    MS CRM 2011 RC中的新特性(8)
    在.NET4中用 jQuery 调用 WCF
    Web打印的在线设计
    MVC3.0RTM版本
    手机刷卡二维码
    Jla框架
    微软Windows Azure Platform技术解析
    缓存应用Memcached分布式缓存简介
    领域驱动设计(DDD)的理论知识
  • 原文地址:https://www.cnblogs.com/gc2013/p/3682687.html
Copyright © 2020-2023  润新知