none
WPF 画 心电图 RRS feed

  • 问题

  • 从串口实时接收到的数据同步画出来,现在用的PathGeometry 动态往里添加LineSegment,但是感觉效率有点低,不希望使用第三方插件如 dynamicdatadisplay等,

    有一个思路,就是重写onRender()方法,但是这会把窗体里的其他控件清掉,不知道该如何重写Canvas的onRender()方法。

    请问如何像GDI+那样实时的画呢?难道WPF解决不了这样的问题吗?

    2013年8月18日 8:45

答案

  • 终于明白啥意思了,多谢指教,可否能贴出完整代码,MinuteQuoteViewModel 这个没有。。。谢谢。

        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
        }

    2014年2月28日 3:09
  • Hi waleswood,

      欢迎来到MSDN中文论坛。

      你可以尝试下面这个办法异步刷新WPF。

     

    1     /// <summary>
     2     /// Designates a Windows Presentation Foundation application model with added functionalities.
     3     /// </summary>
     4      public class UIHelper : Application
     5     {
     6         private static DispatcherOperationCallback exitFrameCallback = new DispatcherOperationCallback(ExitFrame);
     7 
     8         /// <summary>
     9         /// Processes all UI messages currently in the message queue.
    10         /// </summary>
    11         public static void DoEvents()
    12         {
    13             // Create new nested message pump.
    14             DispatcherFrame nestedFrame = new DispatcherFrame();
    15 
    16             // Dispatch a callback to the current message queue, when getting called, 
    17             // this callback will end the nested message loop.
    18             // note that the priority of this callback should be lower than the that of UI event messages.
    19             DispatcherOperation exitOperation = Dispatcher.CurrentDispatcher.BeginInvoke(
    20                 DispatcherPriority.Background, exitFrameCallback, nestedFrame);
    21 
    22             // pump the nested message loop, the nested message loop will 
    23             // immediately process the messages left inside the message queue.
    24             Dispatcher.PushFrame(nestedFrame);
    25 
    26             // If the "exitFrame" callback doesn't get finished, Abort it.
    27             if (exitOperation.Status != DispatcherOperationStatus.Completed)
    28             {
    29                 exitOperation.Abort();
    30             }
    31         }
    32 
    33         private static Object ExitFrame(Object state)
    34         {
    35             DispatcherFrame frame = state as DispatcherFrame;
    36             // Exit the nested message loop.
    37             if (frame != null)
    38             {
    39                 frame.Continue = false;
    40             }
    41             return null;
    42         }
    43 
    44     }


    Jason Wang
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2013年8月19日 8:18
    版主
  • 用 GDI、GDI+或 DirectX2D 来画。

    可以做成 ActiveX 控件,也可以做成 Winform 控件,反正方法很多,也可以直接绘制,比如绘制在 BMP 上,然后绑定到 UI。

    方法很多,你可以上网搜下。对于这种高频数据,一定不能用 WPF 中的对象来做,或者说不能走 WPF 的 UI 渲染,需要程序自己来画。

    2013年8月21日 3:35
  • 明白了,谢谢您!
    2013年9月2日 8:59
  • 您好,GDI+的BMP对象不能在wpf控件下直接用吧,我程序的功能是描绘出由很多点组成的波形,然后实现拖动这个波形的功能,绑定的话是否合理?我试过DrawingVisual画,卡。用InKcanvas.strokes.add(new Stroke(XXX))的方法。拖动效果比 DrawingVisual好一点,还是会卡。但是每次clear()的时候感觉内存没有释放掉,运行一段时间之后内存都占满了。。纯粹用GDI+画的话cpu占用过高,还是会有一点闪,是不是我的数据量太大了,是心电图数据,每2毫秒一个点。这样大的数据量该如何处理才合理,还请不吝赐教~

    1、我得先纠正你的错误观点,BMP 就是 BMP,没有什么 GDI+ 的和 WPF 的之分,只要是 BMP,就算是 C++ /JAVA 都能用;

    2、你用过 WPF 的 Picture 控件吧,我将 1 秒钟的电影转换成 24 张 BMP 图片,然后在 1 秒之内连续、顺序的将这 24 张图片装入到 Picture 控件中,是不是就实现了播放 1 秒钟的电影片段?

    3、GDI+ 比 GDI、DirectX 占用更多的资源,这是不争的事实,虽然你是 2 毫秒的一个点,但是图像的变化并不大,通过局部刷新,可以优化绘制和显式的性能。

    4、我给你提供一段代码,使用 GDI+ 和 WriteableBitmap 的趋势线控件:

        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));
            }
        }

    2014年2月27日 6:41

全部回复

  • Hi waleswood,

      欢迎来到MSDN中文论坛。

      你可以尝试下面这个办法异步刷新WPF。

     

    1     /// <summary>
     2     /// Designates a Windows Presentation Foundation application model with added functionalities.
     3     /// </summary>
     4      public class UIHelper : Application
     5     {
     6         private static DispatcherOperationCallback exitFrameCallback = new DispatcherOperationCallback(ExitFrame);
     7 
     8         /// <summary>
     9         /// Processes all UI messages currently in the message queue.
    10         /// </summary>
    11         public static void DoEvents()
    12         {
    13             // Create new nested message pump.
    14             DispatcherFrame nestedFrame = new DispatcherFrame();
    15 
    16             // Dispatch a callback to the current message queue, when getting called, 
    17             // this callback will end the nested message loop.
    18             // note that the priority of this callback should be lower than the that of UI event messages.
    19             DispatcherOperation exitOperation = Dispatcher.CurrentDispatcher.BeginInvoke(
    20                 DispatcherPriority.Background, exitFrameCallback, nestedFrame);
    21 
    22             // pump the nested message loop, the nested message loop will 
    23             // immediately process the messages left inside the message queue.
    24             Dispatcher.PushFrame(nestedFrame);
    25 
    26             // If the "exitFrame" callback doesn't get finished, Abort it.
    27             if (exitOperation.Status != DispatcherOperationStatus.Completed)
    28             {
    29                 exitOperation.Abort();
    30             }
    31         }
    32 
    33         private static Object ExitFrame(Object state)
    34         {
    35             DispatcherFrame frame = state as DispatcherFrame;
    36             // Exit the nested message loop.
    37             if (frame != null)
    38             {
    39                 frame.Continue = false;
    40             }
    41             return null;
    42         }
    43 
    44     }


    Jason Wang
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2013年8月19日 8:18
    版主
  • 你好,你的意思是还是使用PathGeometry这个方法,然后使用异步刷新吗?

    2013年8月21日 3:24
  • 用 GDI、GDI+或 DirectX2D 来画。

    可以做成 ActiveX 控件,也可以做成 Winform 控件,反正方法很多,也可以直接绘制,比如绘制在 BMP 上,然后绑定到 UI。

    方法很多,你可以上网搜下。对于这种高频数据,一定不能用 WPF 中的对象来做,或者说不能走 WPF 的 UI 渲染,需要程序自己来画。

    2013年8月21日 3:35
  • 明白了,谢谢您!
    2013年9月2日 8:59
  • 用 GDI、GDI+或 DirectX2D 来画。

    可以做成 ActiveX 控件,也可以做成 Winform 控件,反正方法很多,也可以直接绘制,比如绘制在 BMP 上,然后绑定到 UI。

    方法很多,你可以上网搜下。对于这种高频数据,一定不能用 WPF 中的对象来做,或者说不能走 WPF 的 UI 渲染,需要程序自己来画。

    考虑到对xp的支持,还是选择GDI+了,又走回了老路。
    2013年9月2日 13:51
  • 您好,最近回过头来又想尝试用wpf做,请问您说的“绘制在 BMP 上,然后绑定到 UI。”这个具体应该怎么做?
    2014年2月26日 8:39
  • 您好,最近回过头来又想尝试用wpf做,请问您说的“绘制在 BMP 上,然后绑定到 UI。”这个具体应该怎么做?

    WPF控件绑定背景图片,这个你会吗?

    如果会的话,你创建一个 BMP 对象,然后用 GDI+ 在 BMP 对象上绘制,然后把 BMP 绑定到 WPF控件上。


    • 已编辑 Skyseer 2014年2月26日 8:44
    2014年2月26日 8:43
  • 您好,GDI+的BMP对象不能在wpf控件下直接用吧,我程序的功能是描绘出由很多点组成的波形,然后实现拖动这个波形的功能,绑定的话是否合理?我试过DrawingVisual画,卡。用InKcanvas.strokes.add(new Stroke(XXX))的方法。拖动效果比 DrawingVisual好一点,还是会卡。但是每次clear()的时候感觉内存没有释放掉,运行一段时间之后内存都占满了。。纯粹用GDI+画的话cpu占用过高,还是会有一点闪,是不是我的数据量太大了,是心电图数据,每2毫秒一个点。这样大的数据量该如何处理才合理,还请不吝赐教~
    2014年2月27日 3:18
  • 您好,GDI+的BMP对象不能在wpf控件下直接用吧,我程序的功能是描绘出由很多点组成的波形,然后实现拖动这个波形的功能,绑定的话是否合理?我试过DrawingVisual画,卡。用InKcanvas.strokes.add(new Stroke(XXX))的方法。拖动效果比 DrawingVisual好一点,还是会卡。但是每次clear()的时候感觉内存没有释放掉,运行一段时间之后内存都占满了。。纯粹用GDI+画的话cpu占用过高,还是会有一点闪,是不是我的数据量太大了,是心电图数据,每2毫秒一个点。这样大的数据量该如何处理才合理,还请不吝赐教~

    1、我得先纠正你的错误观点,BMP 就是 BMP,没有什么 GDI+ 的和 WPF 的之分,只要是 BMP,就算是 C++ /JAVA 都能用;

    2、你用过 WPF 的 Picture 控件吧,我将 1 秒钟的电影转换成 24 张 BMP 图片,然后在 1 秒之内连续、顺序的将这 24 张图片装入到 Picture 控件中,是不是就实现了播放 1 秒钟的电影片段?

    3、GDI+ 比 GDI、DirectX 占用更多的资源,这是不争的事实,虽然你是 2 毫秒的一个点,但是图像的变化并不大,通过局部刷新,可以优化绘制和显式的性能。

    4、我给你提供一段代码,使用 GDI+ 和 WriteableBitmap 的趋势线控件:

        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));
            }
        }

    2014年2月27日 6:41
  • 终于明白啥意思了,多谢指教,可否能贴出完整代码,MinuteQuoteViewModel 这个没有。。。谢谢。
    2014年2月28日 3:06
  • 终于明白啥意思了,多谢指教,可否能贴出完整代码,MinuteQuoteViewModel 这个没有。。。谢谢。

        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
        }

    2014年2月28日 3:09
  • 能否提供下demo的源码,上面的代码有点乱,没有实际运行成功 看到在高频率下 WPF 心电图的效果、、、
    2014年3月7日 6:46