使用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?
02if (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 
10m_headerLastClicked = DateTime.Now;
11 
12if (Mouse.LeftButton == MouseButtonState.Pressed)
13{
14  DragMove();
15}

 

该如何任意改变窗体大小?
在主窗体的四个角分别添加一个Shape(比如Rectangle)然后为它们都订阅PreviewMouseDown事件处理:
01Rectangle clickedRectangle = (Rectangle)sender;
02    
03switch (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.
03private 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)]
10internal 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.
05protected 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.
22private 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].
33private 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]
62private 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.
05protected 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.
22private 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.
48private 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原创翻译
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页