当我第一次运行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) |
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(null, null); |
10 |
m_headerLastClicked = DateTime.Now; |
12 |
if (Mouse.LeftButton == MouseButtonState.Pressed) |
该如何任意改变窗体大小?
在主窗体的四个角分别添加一个Shape(比如Rectangle)然后为它们都订阅PreviewMouseDown事件处理:
01 |
Rectangle clickedRectangle = (Rectangle)sender; |
03 |
switch (clickedRectangle.Name) |
06 |
Cursor = Cursors.SizeNS; |
07 |
ResizeWindow(ResizeDirection.Top); |
10 |
Cursor = Cursors.SizeNS; |
11 |
ResizeWindow(ResizeDirection.Bottom); |
下面就是用鼠标重新调整窗体大小的代码
01 |
/// <summary> /// Resizes the window. |
02 |
/// </summary> /// <param name="direction">The direction. |
03 |
private void ResizeWindow(ResizeDirection direction) |
05 |
NativeMethods.SendMessage(m_hwndSource.Handle, WM_SYSCOMMAND, |
06 |
(IntPtr)(61440 + direction), IntPtr.Zero); |
09 |
[DllImport("user32.dll", CharSet = CharSet.Auto)] |
10 |
internal static extern IntPtr SendMessage( |
如何为窗体添加阴影效果。
实际上有两种做法:
第一种就是试用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) |
07 |
AllowsTransparency = false; |
08 |
ResizeMode = ResizeMode.NoResize; |
11 |
WindowStartupLocation = WindowStartupLocation.CenterScreen; |
12 |
WindowStyle = WindowStyle.None; |
14 |
SourceInitialized += HandleSourceInitialized; |
16 |
base.OnInitialized(e); |
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) |
24 |
m_hwndSource = (HwndSource)PresentationSource.FromVisual(this); |
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)); |
31 |
// http://msdn.microsoft.com/en-us/library/aa969524(VS.85).aspx |
32 |
Int32 DWMWA_NCRENDERING_POLICY = 2; |
33 |
NativeMethods.DwmSetWindowAttribute( |
35 |
DWMWA_NCRENDERING_POLICY, |
36 |
ref DWMWA_NCRENDERING_POLICY, |
39 |
// http://msdn.microsoft.com/en-us/library/aa969512(VS.85).aspx |
40 |
NativeMethods.ShowShadowUnderWindow(m_hwndSource.Handle); |
无阴影的窗体

有阴影的窗体
第二种方法就是使用四个外部的透明窗体来制造了阴影的假象,如下图所示
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() |
05 |
m_wndT = CreateTransparentWindow(); |
08 |
m_wndL = CreateTransparentWindow(); |
11 |
m_wndB = CreateTransparentWindow(); |
14 |
m_wndR = CreateTransparentWindow(); |
19 |
/// <summary> /// Creates an empty window. |
20 |
/// </summary> /// <returns></returns> private static Window CreateTransparentWindow() |
22 |
Window wnd = new Window(); |
23 |
wnd.AllowsTransparency = true; |
24 |
wnd.ShowInTaskbar = false; |
25 |
wnd.WindowStyle = WindowStyle.None; |
26 |
wnd.Background = null; |
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) |
37 |
Double cornerRadius = 1.75; |
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); |
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"); |
62 |
private Decorator GetDecorator(String imageUri, Double radius = 0) |
64 |
Border border = new Border(); |
65 |
border.CornerRadius = new CornerRadius(radius); |
66 |
border.Background = new ImageBrush( |
68 |
new Uri(BaseUriHelper.GetBaseUri(this), |
计算位置高度的代码
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) |
09 |
LocationChanged += HandleLocationChanged; |
10 |
SizeChanged += HandleLocationChanged; |
11 |
StateChanged += HandleWndStateChanged; |
13 |
InitializeSurrounds(); |
16 |
base.OnInitialized(e); |
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) |
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; |
29 |
m_wndL.Left = Left - m_wndL.Width; |
31 |
m_wndL.Width = c_edgeWndSize; |
32 |
m_wndL.Height = Height; |
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; |
39 |
m_wndR.Left = Left + Width; |
41 |
m_wndR.Width = c_edgeWndSize; |
42 |
m_wndR.Height = Height; |
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) |
50 |
if (WindowState == WindowState.Normal) |
原文链接 , OSChina.NET原创翻译
- 使用WPF来创建 Metro UI程序
本文转载:http://www.cnblogs.com/TianFang/p/3184211.html 这个是我以前网上看到的一篇文章,原文地址是:Building a Metro UI with W ...
- WPF 使用MahApps.Metro UI库
在WPF中要想使用Metro风格是很简单的,可以自己画嘛.. 但是为了节省时间,哈,今天给大家推荐一款国外Metro风格的控件库. 本文只起到抛砖引玉的作用,有兴趣还是推荐大家上官网,Thanks,官 ...
- 收集Windows 8 Metro UI 风格网站资源,觉得不错的顶啊!!
这些资源包含:模板,框架,jQuery插件,图标集等.帮助你快速开发Windows 8 Metro UI风格的网站.本文转自虾米站长网 Frameworks & Templates For M ...
- 7 款免费的 Metro UI 模板
#1 – Free Metro Ui Style template by Asif Aleem 很棒的蓝色调 Metro UI 管理模板 #2: Metro-Bootstrap by TalksLab ...
- 【今日推荐】10大流行的 Metro UI 风格的 Bootstrap 主题和模板
1. BootMetro 基于 Twitter Bootstrap 的简单灵活的 HTML.CSS 和 Javascript 框架,Win8 风格,大爱啊! 立即下载 效果演示 2. Boot ...
- 为WPF项目创建单元测试
原文作者: 周银辉 来源: 博客园 原文地址:http://www.cnblogs.com/zhouyinhui/archive/2007/09/30/911522.html 可能你已发现一个问题, ...
- WPF 跨应用程序域的 UI(Cross AppDomain UI)
为自己写的程序添加插件真的是一个相当常见的功能,然而如果只是简单加载程序集然后去执行程序集中的代码,会让宿主应用程序暴露在非常危险的境地!因为只要插件能够运行任何一行代码,就能将宿主应用程序修改得天翻 ...
- WPF 支持的多线程 UI 并不是线程安全的
原文:WPF 支持的多线程 UI 并不是线程安全的 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可.欢迎转载.使用.重新发布,但务必保留文章署名吕毅(包含链 ...
- Bootstrap看厌了?试试Metro UI CSS吧
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:Bootstrap作为一款超级流行的前端框架,已经成为很多人的首选,不过有时未免有点审 ...
随机推荐
- Java反射机制demo(四)—获取一个类的父类和实现的接口
Java反射机制demo(四)—获取一个类的父类和实现的接口 1,Java反射机制得到一个类的父类 使用Class类中的getSuperClass()方法能够得到一个类的父类 如果此 Class 表示 ...
- 机器学习之路: python nltk 文本特征提取
git: https://github.com/linyi0604/MachineLearning 分别使用词袋法和nltk自然预言处理包提供的文本特征提取 from sklearn.feature_ ...
- BZOJ 3172 [Tjoi2013]单词 AC自动机Fail树
题目链接:[http://www.lydsy.com/JudgeOnline/problem.php?id=3172] 题意:给出一个文章的所有单词,然后找出每个单词在文章中出现的次数,单词用标点符号 ...
- ArrayList,Vector,LinkedList
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 数组列表 和 向量Vector, 都是使用数组方式存储. 向量 使用了 同步synchr ...
- bzoj4399 魔法少女LJJ 线段树合并
只看题面绝对做不出系列.... 注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛) 注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做 操作\(7\)很好处理 ...
- BZOJ.3489.A simple rmq problem(主席树 Heap)
题目链接 当时没用markdown写,可能看起来比较难受...可以复制到别的地方看比如DevC++. \(Description\) 给定一个长为n的序列,多次询问[l,r]中最大的只出现一次的数.强 ...
- Codeforces 1085G(1086E) Beautiful Matrix $dp$+树状数组
题意 定义一个\(n*n\)的矩阵是\(beautiful\)的,需要满足以下三个条件: 1.每一行是一个排列. 2.上下相邻的两个元素的值不同. 再定义两个矩阵的字典序大的矩阵大(从左往右从上到下一 ...
- [Agc011F] Train Service Planning
[Agc011F] Train Service Planning 题目大意: 有n+1个车站,n条轨道,第i条轨道联通i-1和i车站,通过它要花a[i]时间,这条轨道有b[i]=1或2条车道,也就是说 ...
- VC6配置sqlite数据库
SQLite官方下载只提供给我们一个sqlite3.dll跟一个sqlite3.def文件,并没有提供用于VC++6.0的lib文件,可以利用sqlite3.def文件生成,步骤如下: 1.下载DLL ...
- 和程序有关的一个游戏<<mu complex>> 攻略
最速打法: 1 - login, brucedayton 2 - login, allomoto 3 - login, m3g4pa55word 4 - unlock, 03/18/34 5 - ss ...