转载自:http://blog.csdn.net/waleswood/article/details/21744131
作者:waleswood
最近用wpf画心电图,尝试了wpf所有的方法,性能依然不能满足要求,后来发现舍本逐末了,现在记录下来,以免以后再走弯路。
首先要明白wpf管理的机制,如果你往canvas画一条线,一般就是 new Line() 然后添加到canvas里面,这样做的话就算你用轻量级的Polyline,或者使用DrawingVisual的方法。对于高频数据来说(比如心电波形)都会很卡,这里面使用inkcanvas添加stroke的方法效果最好。但是如果你过多执行strokes的clear()和Add,时间一长,内存就会爆掉,InkCanvas 只能胜任轻量级的工作,WPF 会管理 InkCanvas 中的所有元素,例如位置和尺寸, 所以它会消耗大量的内存和 CPU处理时间。InkCanvas 会渲染所有的stroke 在其装饰器层(Adorner Layer)。
可能我对wpf的认识还不足,硬生的把wpf和GDI+隔离开来看了,后来在Just Wang的热心帮助下,终于找到了方法,看他的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212 |
public
class WriteableBitmapTrendLine : FrameworkElement { #region DependencyProperties public
static readonly DependencyProperty LatestQuoteProperty = DependencyProperty.Register( "LatestQuote" , typeof (MinuteQuoteViewModel), typeof (WriteableBitmapTrendLine), new
FrameworkPropertyMetadata( null , FrameworkPropertyMetadataOptions.None, OnLatestQuotePropertyChanged)); private
static void OnLatestQuotePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { WriteableBitmapTrendLine trendLine = (WriteableBitmapTrendLine)d; MinuteQuoteViewModel latestQuote = (MinuteQuoteViewModel)e.NewValue; if
(latestQuote != null ) { trendLine.DrawTrendLine(latestQuote.Ordinal, ( float )latestQuote.LastPx); } } public
MinuteQuoteViewModel LatestQuote { get
{ return
(MinuteQuoteViewModel)GetValue(LatestQuoteProperty); } set
{ SetValue(LatestQuoteProperty, value); } } #endregion private
const int COLS = 723; private
const int ROWS = 41; private
WriteableBitmap bitmap; private
float maxPrice = 0.0F; private
static int dx = 3; private
float [] prices = new
float [COLS / dx]; public
WriteableBitmapTrendLine() { this .bitmap = new
WriteableBitmap(COLS, ROWS, 96, 96, PixelFormats.Rgb24, null ); this .bitmap.Lock(); using
(Bitmap backBufferBitmap = new
Bitmap(COLS, ROWS, this .bitmap.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, this .bitmap.BackBuffer)) { using
(Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap)) { backBufferGraphics.Clear(System.Drawing.Color.WhiteSmoke); backBufferGraphics.Flush(); } } this .bitmap.AddDirtyRect( new
Int32Rect(0, 0, COLS, ROWS)); this .bitmap.Unlock(); } private
void DrawTrendLine( int
ordinal, float
latestPrice) { if
( double .IsNaN(latestPrice)) return ; this .prices[ordinal] = latestPrice; bool
redraw = false ; if
(ordinal == 0) { this .maxPrice = latestPrice; } else { if
(latestPrice > this .maxPrice) { this .maxPrice = latestPrice; redraw = true ; } } if
(ordinal == 0) { int
width = this .bitmap.PixelWidth; int
height = this .bitmap.PixelHeight; this .bitmap.Lock(); using
(Bitmap backBufferBitmap = new
Bitmap(width, height, this .bitmap.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, this .bitmap.BackBuffer)) { using
(Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap)) { backBufferGraphics.Clear(System.Drawing.Color.WhiteSmoke); backBufferGraphics.Flush(); } } this .bitmap.AddDirtyRect( new
Int32Rect(0, 0, width, height)); this .bitmap.Unlock(); } else { System.Drawing.Point[] points = new
System.Drawing.Point[ordinal + 1]; float
dy = ( float )(ROWS / ( this .maxPrice * 1.3)); for
( int
i = 0; i <= ordinal; i++) { points[i].X = i * dx; points[i].Y = ( int )( this .prices[i] * dy); } int
width = ordinal * dx + 1; int
height = this .bitmap.PixelHeight; this .bitmap.Lock(); using
(Bitmap backBufferBitmap = new
Bitmap(width, height, this .bitmap.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, this .bitmap.BackBuffer)) { using
(Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap)) { backBufferGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; backBufferGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed; if
(redraw) backBufferGraphics.Clear(System.Drawing.Color.WhiteSmoke); backBufferGraphics.DrawLines(System.Drawing.Pens.Green, points); backBufferGraphics.Flush(); } } this .bitmap.AddDirtyRect( new
Int32Rect(0, 0, width, height)); this .bitmap.Unlock(); } } private
void DrawTrendLineF( int
ordinal, float
latestPrice) { if
( double .IsNaN(latestPrice)) return ; this .prices[ordinal] = latestPrice; if
(ordinal == 0) { this .maxPrice = latestPrice; } else { if
(latestPrice > this .maxPrice) { this .maxPrice = latestPrice; } } if
(ordinal == 0) { int
width = this .bitmap.PixelWidth; int
height = this .bitmap.PixelHeight; this .bitmap.Lock(); using
(Bitmap backBufferBitmap = new
Bitmap(width, height, this .bitmap.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, this .bitmap.BackBuffer)) { using
(Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap)) { backBufferGraphics.Clear(System.Drawing.Color.WhiteSmoke); backBufferGraphics.Flush(); } } this .bitmap.AddDirtyRect( new
Int32Rect(0, 0, width, height)); this .bitmap.Unlock(); } else { int
count = this .prices.Length; PointF[] points = new
PointF[ordinal + 1]; float
dy = ( float )(ROWS / this .maxPrice); for
( int
i = 0; i <= ordinal; i++) { points[i].X = i; points[i].Y = ( float )Math.Floor( this .prices[i] * dy); if
( float .IsNaN(points[i].Y)) points[i].Y = 0.0F; } int
width = ordinal + 1; int
height = this .bitmap.PixelHeight; this .bitmap.Lock(); using
(Bitmap backBufferBitmap = new
Bitmap(width, height, this .bitmap.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, this .bitmap.BackBuffer)) { using
(Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap)) { backBufferGraphics.DrawLines(System.Drawing.Pens.Green, points); backBufferGraphics.Flush(); } } this .bitmap.AddDirtyRect( new
Int32Rect(0, 0, width, height)); this .bitmap.Unlock(); } } protected
override void OnRender(DrawingContext drawingContext) { drawingContext.PushTransform( new
ScaleTransform(1, -1, 0, RenderSize.Height / 2)); drawingContext.DrawImage(bitmap, new
Rect(0, 0, RenderSize.Width, RenderSize.Height)); } } |
public class MinuteQuoteViewModel : INotifyPropertyChanged { private int ordinal; public int Ordinal { get { return this.ordinal; } set { if (this.ordinal != value) { this.ordinal = value; this.OnPropertyChanged("Ordinal"); } } } private DateTime quoteTime; public DateTime QuoteTime { get { return this.quoteTime; } set { if (this.quoteTime != value) { this.quoteTime = value; this.OnPropertyChanged("QuoteTime"); } } } private double lastPx = double.NaN; public double LastPx { get { return this.lastPx; } set { if (this.lastPx != value) { this.lastPx = value; this.OnPropertyChanged("LastPx"); } } } private double avgPx = double.NaN; public double AvgPx { get { return this.avgPx; } set { if (this.avgPx != value) { this.avgPx = value; this.OnPropertyChanged("AvgPx"); } } } private int volume; public int Volume { get { return this.volume; } set { if (this.volume != value) { this.volume = value; this.OnPropertyChanged("Volume"); } } } private double amount = double.NaN; public double Amount { get { return this.amount; } set { if (this.amount != value) { this.amount = value; this.OnPropertyChanged("Amount"); } } } #region INotifyPropertyChanged 成员 public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } #endregion }
他这个应该是直接从项目上拔下来的,看着比较费劲,我在vs2013下写了一个简单的示例,取消了固定区域,转为自适应界面。
代码下载:http://download.csdn.net/detail/waleswood/7079287
原文:http://www.cnblogs.com/changbiao/p/3664250.html