首页 > 其他 > 详细

WPF画图性能问题

时间:2014-04-15 08:38:07      阅读:568      评论:0      收藏:0      [点我收藏+]

转载自: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));
        }
    }

 

 

 

bubuko.com,布布扣
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
    }
bubuko.com,布布扣

 

他这个应该是直接从项目上拔下来的,看着比较费劲,我在vs2013下写了一个简单的示例,取消了固定区域,转为自适应界面。

 

代码下载:http://download.csdn.net/detail/waleswood/7079287

相关帖子地址:http://social.msdn.microsoft.com/Forums/zh-CN/3baebf07-5a0e-4e3a-a588-b79d869d6d47/inkcanvasstrokesclear?forum=wpfzhchs#7ce0efd9-7254-4d98-9d86-427d820cd827

http://social.msdn.microsoft.com/Forums/zh-CN/febcee07-dc8b-44b4-8c0a-246daffdbe2b/wpf-?forum=wpfzhchs#bfadef47-ab7b-4f8b-9340-e3c7a2782b76

http://social.msdn.microsoft.com/Forums/zh-CN/b156e12b-bc52-44a9-b2f9-26fff723cff5/wpf-inkcanvas?forum=wpfzhchs#de6c4b50-7036-4823-bbec-4e9ba309a600

 

 

WPF画图性能问题,布布扣,bubuko.com

WPF画图性能问题

原文:http://www.cnblogs.com/changbiao/p/3664250.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!