Захват формы в растровое изображение после изменения размера формы

Работая в C# у меня есть проект с требованием захватить Control или же Form в растровое изображение. У меня есть класс, который занимает Control параметр в конструкторе, а затем выполняет следующий код (упрощенный для этого примера), чтобы сохранить растровое изображение Control,

public MyItem(Control control)
    {
        if (control != null)
        {
            Control rootParent = control;
            while (rootParent.Parent != null)
                rootParent = rootParent.Parent;

            rootParent.BringToFront();

            _bounds = control.Bounds;
            Rectangle controlBounds;

            if (control.Parent == null)
            {
                _bounds = new Rectangle(new Point(0, 0), control.Bounds.Size);
                controlBounds = _bounds;
            }
            else
            {
                _bounds.Intersect(control.Parent.ClientRectangle);
                _bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size);
                controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size);
            }

            if (_bounds.Height > 0 && _bounds.Width > 0)
            {
                IntPtr hDC = IntPtr.Zero;

                if (control.Parent == null && !Clarity.ClientAreaOnly)
                    // Used for capturing a form including non-client area
                    hDC = Win32.GetWindowDC(control.Handle);
                else
                    // Used for capturing a form excluding non-client area or a control
                    hDC = control.CreateGraphics().GetHdc();

                try
                {
                    _controlBitmap = new Bitmap(_bounds.Width, _bounds.Height);
                    using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap))
                    {
                        IntPtr bitmapHandle = bitmapGraphics.GetHdc();
                        Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376);
                        bitmapGraphics.ReleaseHdc(bitmapHandle);
                    }
                }
                finally
                {
                    if (hDC != IntPtr.Zero)
                        Win32.ReleaseDC(control.Handle, hDC);
                }
            }
        }
    }

Экземпляр этого класса создается для каждого элемента управления, который мне нужен для захвата, используется растровое изображение (в данном случае оно выводится на экран), и объект удаляется, когда он больше не нужен. Это прекрасно работает и дает мне растровое изображение указанного Control или же Form, включая не клиентскую область в случае последней, как показано ниже:

http://i.imgur.com/ZizXjNX.png

Однако, если я попытаюсь захватить Form опять сталкиваюсь с проблемами. Если я изменил размер Form перед повторным захватом второй захват покажет неверную область, не относящуюся к клиенту.

Ниже показано изображение, чтобы проиллюстрировать это - слева - то, как форма выглядит на экране (правильно), а справа - как этот код ее фиксирует (неправильно).

http://i.imgur.com/y46kFDj.png

Я не придумал ничего из моих собственных поисков и поэтому задавался вопросом, может ли кто-то указать на то, что я делаю неправильно / не делаю?

1 ответ

Я не смог решить эту проблему должным образом (сохранив существующий метод захвата), и, поскольку это касается прототипа приложения, у меня сейчас нет времени, чтобы углубляться в него. Если этот прототип будет поднят или у меня будет еще одна возможность изучить это снова, я обновлю этот ответ соответственно.

В то же время я использовал следующий подход в качестве альтернативы. Это производит вывод по желанию, хотя и использует другой механизм для захвата контента. Я не очень люблю это, так как это "портит" окна и формы больше, чем хотелось бы, но пока этого достаточно.

По сути, я просто перенес интересующее окно / форму на передний план, установил его на самый верхний, а затем сделал снимок экрана только на границах окна. Как я уже сказал, грязнее, чем хотелось бы, но на практике это работает достаточно хорошо!

public MyItem(Control control)
{
    if (control != null)
    {
        Control rootParent = control;
        while (rootParent.Parent != null)
            rootParent = rootParent.Parent;

        rootParent.BringToFront();

        _bounds = control.Bounds;
        Rectangle controlBounds;

        if (control.Parent == null)
        {
            _bounds = new Rectangle(new Point(0, 0), control.Bounds.Size);
            controlBounds = _bounds;
        }
        else
        {
            _bounds.Intersect(control.Parent.ClientRectangle);
            _bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size);
            controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size);
        }

        if (_bounds.Height > 0 && _bounds.Width > 0)
        {
            _controlBitmap = new Bitmap(_bounds.Width, _bounds.Height);
            using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap))
            {
                if (control.Parent == null)
                {
                    Form form = control as Form;
                    Boolean currentTopMost = form.TopMost;
                    form.TopMost = true;
                    control.BringToFront();
                    bitmapGraphics.CopyFromScreen(control.Location, Point.Empty, _bounds.Size);
                    form.TopMost = currentTopMost;
                }
                else
                {
                    IntPtr hDC = IntPtr.Zero;
                    try
                    {
                        hDC = control.CreateGraphics().GetHdc();
                        IntPtr bitmapHandle = bitmapGraphics.GetHdc();
                        Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376);
                        bitmapGraphics.ReleaseHdc(bitmapHandle);
                    }
                    finally
                    {
                        if (hDC != IntPtr.Zero)
                            Win32.ReleaseDC(control.Handle, hDC);
                    }
                }
            }
        }
    }
}
Другие вопросы по тегам