使用WPF來創建 Metro UI
當我第一次運行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事件處理。
// Is this a double-click? if (DateTime.Now.Subtract(m_headerLastClicked) <= s_doubleClick) { // Execute the code inside the event handler for the // restore button click passing null for the sender // and null for the event args. HandleRestoreClick(null, null); } m_headerLastClicked = DateTime.Now; if (Mouse.LeftButton == MouseButtonState.Pressed) { DragMove(); }
該如何任意改變窗體大小?
在主窗體的四個角分別添加一個Shape(比如Rectangle)然后為它們都訂閱PreviewMouseDown事件處理:
Rectangle clickedRectangle = (Rectangle)sender; switch (clickedRectangle.Name) { case "top": Cursor = Cursors.SizeNS; ResizeWindow(ResizeDirection.Top); break; case "bottom": Cursor = Cursors.SizeNS; ResizeWindow(ResizeDirection.Bottom); break; // ... }
下面就是用鼠標重新調整窗體大小的代碼
////// Resizes the window. /// /// The direction. private void ResizeWindow(ResizeDirection direction) { NativeMethods.SendMessage(m_hwndSource.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero); } [DllImport("user32.dll", CharSet = CharSet.Auto)] internal static extern IntPtr SendMessage( IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
如何為窗體添加陰影效果。
實際上有兩種做法:
第一種就是試用DWM API。這個方法需要訂閱SourceInitialized事件。
///無陰影的窗體/// Raises the /// Theevent. /// This method is invoked whenever /// /// is set to true internally. /// /// that contains the event data. protected override void OnInitialized(EventArgs e) { AllowsTransparency = false; ResizeMode = ResizeMode.NoResize; Height = 480; Width = 852; WindowStartupLocation = WindowStartupLocation.CenterScreen; WindowStyle = WindowStyle.None; SourceInitialized += HandleSourceInitialized; base.OnInitialized(e); } /// /// Handles the source initialized. /// /// The sender. /// The/// instance containing the event data. private void HandleSourceInitialized(Object sender, EventArgs e) { m_hwndSource = (HwndSource)PresentationSource.FromVisual(this); // Returns the HwndSource object for the window // which presents WPF content in a Win32 window. HwndSource.FromHwnd(m_hwndSource.Handle).AddHook( new HwndSourceHook(NativeMethods.WindowProc)); // http://msdn.microsoft.com/en-us/library/aa969524(VS.85).aspx Int32 DWMWA_NCRENDERING_POLICY = 2; NativeMethods.DwmSetWindowAttribute( m_hwndSource.Handle, DWMWA_NCRENDERING_POLICY, ref DWMWA_NCRENDERING_POLICY, 4); // http://msdn.microsoft.com/en-us/library/aa969512(VS.85).aspx NativeMethods.ShowShadowUnderWindow(m_hwndSource.Handle); }

有陰影的窗體

第二種方法就是使用四個外部的透明窗體來制造了陰影的假象,如下圖所示

1,用代碼的方式創建一個透明的窗體
2,找到Main Window 在屏幕上的坐標,尤其是左上角
3,計算4個透明窗口的坐標
4,當我們移動Main Window時,4個邊框透明窗口也需要跟著移動
5,當我們重新設定 Main Window大小時,4個邊框透明窗口也要跟著變化大小。
說這么多看上去好像很難,來讓我們看看實現的代碼吧。
創建透明窗體的代碼
////// Initializes the surrounding windows. /// private void InitializeSurrounds() { // Top. m_wndT = CreateTransparentWindow(); // Left. m_wndL = CreateTransparentWindow(); // Bottom. m_wndB = CreateTransparentWindow(); // Right. m_wndR = CreateTransparentWindow(); SetSurroundShadows(); } ////// Creates an empty window. /// ///private static Window CreateTransparentWindow() { Window wnd = new Window(); wnd.AllowsTransparency = true; wnd.ShowInTaskbar = false; wnd.WindowStyle = WindowStyle.None; wnd.Background = null; return wnd; } /// /// Sets the artificial drop shadow. /// /// if set totrue [active]. private void SetSurroundShadows(Boolean active = true) { if (active) { Double cornerRadius = 1.75; m_wndT.Content = GetDecorator( "Images/ACTIVESHADOWTOP.PNG"); m_wndL.Content = GetDecorator( "Images/ACTIVESHADOWLEFT.PNG", cornerRadius); m_wndB.Content = GetDecorator( "Images/ACTIVESHADOWBOTTOM.PNG"); m_wndR.Content = GetDecorator( "Images/ACTIVESHADOWRIGHT.PNG", cornerRadius); } else { m_wndT.Content = GetDecorator( "Images/INACTIVESHADOWTOP.PNG"); m_wndL.Content = GetDecorator( "Images/INACTIVESHADOWLEFT.PNG"); m_wndB.Content = GetDecorator( "Images/INACTIVESHADOWBOTTOM.PNG"); m_wndR.Content = GetDecorator( "Images/INACTIVESHADOWRIGHT.PNG"); } } [DebuggerStepThrough] private Decorator GetDecorator(String imageUri, Double radius = 0) { Border border = new Border(); border.CornerRadius = new CornerRadius(radius); border.Background = new ImageBrush( new BitmapImage( new Uri(BaseUriHelper.GetBaseUri(this), imageUri))); return border; }
計算位置高度的代碼
原文鏈接 , OSChina.NET原創翻譯
////// Raises the /// Theevent. /// This method is invoked whenever /// /// is set to true internally. /// /// that contains the event data. protected override void OnInitialized(EventArgs e) { // ... LocationChanged += HandleLocationChanged; SizeChanged += HandleLocationChanged; StateChanged += HandleWndStateChanged; InitializeSurrounds(); ShowSurrounds(); base.OnInitialized(e); } /// /// Handles the location changed. /// /// The sender. /// The/// instance containing the event data. private void HandleLocationChanged(Object sender, EventArgs e) { m_wndT.Left = Left - c_edgeWndSize; m_wndT.Top = Top - m_wndT.Height; m_wndT.Width = Width + c_edgeWndSize * 2; m_wndT.Height = c_edgeWndSize; m_wndL.Left = Left - m_wndL.Width; m_wndL.Top = Top; m_wndL.Width = c_edgeWndSize; m_wndL.Height = Height; m_wndB.Left = Left - c_edgeWndSize; m_wndB.Top = Top + Height; m_wndB.Width = Width + c_edgeWndSize * 2; m_wndB.Height = c_edgeWndSize; m_wndR.Left = Left + Width; m_wndR.Top = Top; m_wndR.Width = c_edgeWndSize; m_wndR.Height = Height; } /// /// Handles the windows state changed. /// /// The sender. /// The/// instance containing the event data. private void HandleWndStateChanged(Object sender, EventArgs e) { if (WindowState == WindowState.Normal) { ShowSurrounds(); } else { HideSurrounds(); } }
原文鏈接 , OSChina.NET原創翻譯
本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!