捕获控件'用于离线渲染的OnPaint事件

时间:2014-07-02 16:51:02

标签: c# .net wpf winforms

我在将旧的Windows窗体世界和WPF世界结合在一起时遇到了一些麻烦。最初的问题是我们总是需要一个WindowsFormsHost来托管我们的窗体控件,尤其是用于显示图形的Chart控件。

由于我们还需要客户端/服务器支持,我的想法是创建一个Windows窗体并将图表添加为子窗口。出于这个原因,我创建了一个OffscreenForm(BackEnd),我转移到窗口不可见的位置(例如X = -10000,Y = -10000)。

然后我将FrontEnd WPF控件附加到用户定义的OnPaint方法,该方法每次BackEnd更改时都会更新。 OnPaint中的问题是只渲染可见部分。因此我使用了OnPrint,但DrawToImage有一个内存错误,并没有正确清理。我还将鼠标事件从FrontEnd传输到BackEnd。

简而言之:有人试图创造类似的东西。我当前的大部分解决方案都运行正常,但在OnPaint / OnPrint之间我不太了解一些小事。

这是我的代码。它看起来有点难看。有些事情只是在事情发生时看到的东西。

如果有人有解决方案在刷新/重绘时获取控件的图像,那就太棒了。

由于 马丁

后端:

using siemens.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace formshost
{
    public class OffscreenWindowsFormsRenderer : Control
    {
        public event EventHandler<MemoryStream> MyPaint;
        System.Windows.Forms.Form form = new System.Windows.Forms.Form();

        List<Point> pts = new List<Point>();

        int x = 10;
        public OffscreenWindowsFormsRenderer(Control ctrl)
            : base()
        {
            Application.EnableVisualStyles();

            form = new System.Windows.Forms.Form();
            form.CreateControl();
            form.SetBounds(-10000, 300, 0, 0, System.Windows.Forms.BoundsSpecified.Location);
            form.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
            form.Show();
            form.Controls.Add(this);


            CreateControl();

            BackColor = Color.Lime;

            Controls.Add(ctrl);

            //FireImage();

            Timer T = new Timer();
            T.Tick += T_Tick;
            T.Start();
        }

        void T_Tick(object sender, EventArgs e)
        {
            Refresh();
            x += 5;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.FillRectangle(Brushes.Yellow, x, x, 50, 50);

            lock (pts)
            {
                if (pts.Count > 1)
                    e.Graphics.DrawLines(Pens.Red, pts.ToArray());
            }

            FireImage();
        }

        protected override void OnPrint(PaintEventArgs e)
        {
            base.OnPrint(e);        

            //FireImage();
        }

        Bitmap bmp;

        void FireImage()
        {

            lock (this)
            {
                int W = Width;
                int H = Height;

                if (bmp != null)
                {
                    if (bmp.Width != W || bmp.Height != H)
                    {
                        bmp.Dispose();
                        bmp = null;
                    }
                }

                if (bmp == null)
                {
                    if (W > 0 && H > 0)
                        bmp = new Bitmap(W, H, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                }

                if (bmp != null)
                {
                    DrawToBitmapExtended(bmp, new Rectangle(0, 0, W, H));
                    MemoryStream mem = new MemoryStream();
                    bmp.Save(mem, ImageFormat.Bmp);

                    MyPaint(this, mem);
                }

                //    using(Graphics g
            }
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            FireImage();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            Refresh();            
        }

        public void MouseMove(IntPtr wparam, IntPtr lparam)
        {
            //Message msg = Message.Create(this.Handle, User.WM_MOUSEMOVE, wparam, lparam);
            SendMessage(this.Handle, User.WM_MOUSEMOVE, wparam, lparam);
            FireImage();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            lock (pts)
            {
                pts.Add(e.Location);
            }
        }

        Bitmap tempimage;

        public void DrawToBitmapExtended(Bitmap bitmap, Rectangle targetBounds)
        {
            if (bitmap == null)
            {
                throw new ArgumentNullException("bitmap");
            }

            if (targetBounds.Width <= 0 || targetBounds.Height <= 0
                || targetBounds.X < 0 || targetBounds.Y < 0)
            {
                throw new ArgumentException("targetBounds");
            }

            if (!IsHandleCreated)
            {
                CreateHandle();
            }


            int width = Math.Min(this.Width, targetBounds.Width);
            int height = Math.Min(this.Height, targetBounds.Height);

            if (tempimage != null)
            {
                if (tempimage.Width != width || tempimage.Height != height)
                {
                    tempimage.Dispose();
                    tempimage = null;
                }
            }

      //     if (tempimage == null)
                tempimage = new Bitmap(width, height, bitmap.PixelFormat);

                using (Graphics g = Graphics.FromImage(tempimage))
            {
                IntPtr hDc = g.GetHdc();

                //send the actual wm_print message
                SendMessage(this.Handle, WM_PRINT, (IntPtr)hDc,
                    (IntPtr)(PRF_CHILDREN | PRF_CLIENT | PRF_NONCLIENT ));

                //now BLT the result to the destination bitmap.

                using (Graphics destGraphics = Graphics.FromImage(bitmap))
                {
                    IntPtr desthDC = destGraphics.GetHdc();
                    BitBlt(desthDC, targetBounds.X, targetBounds.Y, width, height,
                                             hDc, 0, 0, 0x00CC0020);
                    destGraphics.ReleaseHdc(desthDC);
                }
                g.ReleaseHdc(hDc);
            }
        }

        const int PRF_NONCLIENT = 0x00000002,
             PRF_CLIENT = 0x00000004,
             PRF_ERASEBKGND = 0x00000008,
        PRF_CHILDREN = 0x00000010,
        WM_PRINT = 0x0317,
        WM_PRINTCLIENT = 0x0318,
        PRF_OWNED = 0x0020;


        [DllImport("gdi32.dll")]
        static extern int SetROP2(IntPtr hdc, int fnDrawMode);

        [DllImport("User32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        [ResourceExposure(ResourceScope.None)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("Gdi32.dll", SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        [ResourceExposure(ResourceScope.None)]
        public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight,
                                         IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);

    }
}

前端:

using formshost;
using siemens.Win32;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication6
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        OffscreenWindowsFormsRenderer off;
        System.Windows.Forms.PictureBox box = new System.Windows.Forms.PictureBox();

        public MainWindow()
        {
            InitializeComponent();
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);

            PanelFast fast = new PanelFast();

            myGrid.Children.Add(fast);
            Grid.SetRow(fast, 1);

            box.Width = 100;
            box.Height = 100;
            box.Image = new Bitmap("D:\\image.jpg");
            //box.Dock = System.Windows.Forms.DockStyle.Fill;
            box.Show();


            off = new OffscreenWindowsFormsRenderer(box);
            off.Visible = true;

            fast.SetRenderer(off);
        }
    }

    public class PanelFast : Panel
    {
        public OffscreenWindowsFormsRenderer Renderer
        {
            get;
            private set;
        }

        BitmapImage myBitmap = null;

        public void SetRenderer(OffscreenWindowsFormsRenderer r)
        {
            Renderer = r;
            Renderer.MyPaint += off_MyPaint;
        }

        void off_MyPaint(object sender, MemoryStream e)
        {
            myBitmap = new BitmapImage();

            myBitmap.BeginInit();
            myBitmap.StreamSource = e;
            myBitmap.EndInit();
            myBitmap.Freeze();

            SnapsToDevicePixels = true;


            InvalidateVisual();
        }

        public PanelFast()
        {
            SizeChanged += PanelFast_SizeChanged;
        }

        void PanelFast_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Renderer.SetBounds(0, 0, (int)ActualWidth, (int)ActualHeight, System.Windows.Forms.BoundsSpecified.Size);
        }

        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);
            dc.DrawImage(myBitmap, new Rect(0, 0, ActualWidth, ActualHeight));
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            Renderer.MouseMove((IntPtr)0, (IntPtr)GetXY(e.GetPosition(this)));
        }

        int GetXY(System.Windows.Point pt)
        {
            int x = (int)(pt.X);
            int y = (int)(pt.Y);

            return y << 16 | x;
        }
    }
}

0 个答案:

没有答案