【翻译】关于 WPF 透明窗口的内存占用

【翻译】关于 WPF 透明窗口的内存占用

翻译自己的文章才是最骚的。。。 Origin Post


要实现一个透明的 WPF 窗口?
多么简单的一个任务啊!只要设置 AllowTransparency 和 WindowStyle,你可以在毫秒间完成这个任务。

AllowTransparency="True" WindowStyle="None" Background="Transparent"

正确吧?当然。
但是(你懂得),打开你的任务管理器看看,简单的任务通常会带来大量的内存占用,特别是4K分辨率的透明窗口。100+ MB的内存被浪费了,就只为了显示一个空白的透明窗口!这是不可接受的。一年前,如果你说:”谁关心内存呀,现在的内存条太便宜了”,你可能是对的。但是查查这一年内存条的价格走向,它们现在贵上天了。

WPF 透明窗口的有趣小真相

  • 内存占用随着窗口尺寸增大而增加
  • Win32 窗口没有这样的问题

等等,什么?窗口越大,内存消耗的更多?嗯。。。这看起来很熟悉嘛,就像一个Bitmap。知道现在,我们并不知道 WPF 是如何处理透明窗口的,但是这种症状显示它就好像直接将整个桌面作为一个位图,然后窗口用这张位图的重叠部分作为其背景来更新自己,让它看起来是“透明”的。多么聪明的做法呀。。。
在 WPF 刚刚发布的那些日子里,低分辨率的计算机屏幕占据主流位置,即使在今天,大多数的笔记本电脑依然带着一块1366*768分辨率的屏幕被推向市场(离谱吧)。让我们唾弃那些OEM厂商讲的毫无根据的废话并且思考一下运行在高分辨率下的程序的情况。

内存并不是免费的,不要浪费之

很显然,浪费100+MB的内存来显示一个4K的透明窗口是不可接受的,特别是和 Win32 窗口只占用10+MB的内存进行比较时。这差距让 WPF 看起来蠢透了。
抱怨已经够多了,想想对此我们能做什么呢?我可不想用C++和GDI将我的UI代码重写一遍,这太没效率并且也跟不上时代,况且,没人会为此“区区小事”去放弃他们漂亮、易于维护的Xaml UI代码。

使用 Win32 承载 WPF 内容

好吧,确实,没人愿意为了区区90MB内存去重写它们的UI。与使用C++重写UI所耗费的精力相比,这个内存的占用差距看起来是可以接受的(#笑脸)。但是请记住,我们一如既往的可以在 Win32 窗口中承载 WPF 的内容。
例如,我们想创建一个全屏、半透明背景带着非透明内容的对话框。为了规避 WPF 透明窗口的内存问题,我们可以使用 Win32 创建一个半透明的窗口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DWORD Flags1 = WS_EX_LAYERED;
DWORD Flags2 = WS_POPUP;

HWND hWnd = CreateWindowEx(Flags1,szWindowClass, szTitle, Flags2,
CW_USEDEFAULT, 0, 3840,2160, nullptr, nullptr, hInstance, nullptr);

SetLayeredWindowAttributes(hWnd, RRR, (BYTE)125, LWA_ALPHA);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

case WM_ERASEBKGND:
RECT rect;
GetClientRect(hWnd, &rect);
FillRect((HDC)wParam, &rect, CreateSolidBrush(RGB(0, 0, 0)));
break;

通过启用 C++/CLI,我们可以直接访问 WPF 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace ManagedCode
{
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Interop;
using namespace System::Windows::Media;

HWND GetHwnd(HWND parent, int x, int y, int width, int height) {
HwndSource^ source = gcnew HwndSource(
0, // class style
WS_VISIBLE | WS_CHILD, // style
0, // exstyle
x, y, width, height,
"hi", // NAME
IntPtr(parent) // parent window
);

UIElement^ page = gcnew ManagedContent::WPFContent();
source->RootVisual = page;
return (HWND)source->Handle.ToPointer();
}
}

最后

1
2
//managed content
ManagedCode::GetHwnd(hWnd, 0, 0, 200, 200);

由于 WPF 和 GDI 背后的技术不尽相同,还有更多的工作需要做来解决不可避免的透明通道问题,但是,为了方便,你始终可以使用 Popup 来实现你的目标。


Macbook Pro 2016 的键盘真垃圾。。。。。。

【翻译】There Is No Thread

【翻译】There Is No Thread

这里并没有线程

原文地址: http://blog.stephencleary.com/2013/11/there-is-no-thread.html


最纯粹的async形式中存在一个重要的真相:这里并没有线程(或者不存在新建的线程)
举不胜数的反对者哭喊道:“不!如果我正在等待一个操作,那一定存在一个线程在等待这个操作!它可能是一个线程池中的线程。或者是系统线程!或者是其他类似设备驱动的东西…”。

不要听从那些哭喊的人。如果那些async操作是纯粹的,那么这里将不会存在线程。

阅读更多
深挖 WPF 渲染系统

深挖 WPF 渲染系统

这是一篇2011年的文章,原地址在 A Critical Deep Dive into the WPF Rendering System,个人认为到现在都可以给WPF程序开发人员作为一个参考,里面详细讲述了 WPF 这个号称从底层支持硬件加速的 UI 框架为什么有时候看起来并不是那么回事的原因。以下是正文。


刚开始我并不认为我会发表这篇文章。在被一些我高度重视的人说服后,我决定要发表这篇文章。那些深入投入微软UX平台的程序员应该更加深入了解这个平台内部是怎么工作的,当他们撞到一睹石墙的时候,他们可以清晰了解到问题所在并且更加准确地沟通他们希望平台做出怎样的改变。

我相信 WPF 和 Silverlight 是精心打造的技术,但是…

如果这几个月你有关注我的Twitter,你也许会发现我一直在吐槽WPF(Silverlight也一样)的性能。为什么我会这样做?毕竟这些年我花费了大量的时间为这个平台布道、写库、社区帮助和指导等等。准确来讲,我个人全身投入到这个平台里面,我希望这个平台越来越好。

性能,性能,性能

当在开发沉浸式的、消费者导向的UX的时候,性能是你第一位的特性。性能是你添加其他特性的前提和基础。有多少次因为UI太卡你需要缩小UI的规模?有多少次因为这个技术做不到所以你需要丢弃“开创性的UX模型”?有多少次你告诉客户他们需要一个2.4GHz的四核CPU才能获得全部的体验?我一直以来都被客户问,为什么在PC上拥有4倍于iPad的性能的情况下,WPF程序却做不到像iPad应用那般流畅?

阅读更多