1

I'm looking for possibility to create a live preview of WinForms Form/Control. My application got two windows - one, where someone can draw on Image (which is in PictureBox), and second window, where someone can see what was been drawn on 1st window. At this moment, I tried to put the same PictureBox with image on second window, and draw the same lines on it like in window 1. Unfortunately preview like this is not live preview, because image on window 2 is refreshed when someone stop drawing on window 1. Below I'm sending a code, which is used to draw on Image.

public void AddNewPoint(int X, int Y)
{
    if (_firstPointInStroke)
    {
        _firstpoint = _mainCustomPictureBox.PointToClient(new System.Drawing.Point(X, Y));
        _firstPointInStroke = false;
            }
        _secondpoint = _mainCustomPictureBox.PointToClient(new System.Drawing.Point(X, Y));

        var g = Graphics.FromImage(_mainCustomPictureBox.Image);

        var wfactor = (double)_mainCustomPictureBox.Image.Width / _mainCustomPictureBox.Width;
        var hfactor = (double)_mainCustomPictureBox.Image.Height / _mainCustomPictureBox.Height;
        var resizeFactor = Math.Max(wfactor, hfactor);
        System.Windows.Shapes.Line currentLine;
        if (hfactor > wfactor)
        {
            _firstpoint.X = (float)((_firstpoint.X - ((_mainCustomPictureBox.Width - ((double)_mainCustomPictureBox.Image.Width / resizeFactor)) / 2)) * resizeFactor);
            _firstpoint.Y = (float)(_firstpoint.Y * resizeFactor);
            _secondpoint.X = (float)((_secondpoint.X - ((_mainCustomPictureBox.Width - ((double)_mainCustomPictureBox.Image.Width / resizeFactor)) / 2)) * resizeFactor);
            _secondpoint.Y = (float)(_secondpoint.Y * resizeFactor);
        }
        else
        {
            _firstpoint.X = (float)(_firstpoint.X * resizeFactor);
            _firstpoint.Y = (float)((_firstpoint.Y - ((_mainCustomPictureBox.Height - ((double)_mainCustomPictureBox.Image.Height / resizeFactor)) / 2)) * resizeFactor);
            _secondpoint.X = (float)(_secondpoint.X * resizeFactor);
            _secondpoint.Y = (float)((_secondpoint.Y - ((_mainCustomPictureBox.Height - ((double)_mainCustomPictureBox.Image.Height / resizeFactor)) / 2)) * resizeFactor);
        }
        currentLine = new System.Windows.Shapes.Line { X1 = _firstpoint.X, X2 = _secondpoint.X, Y1 = _firstpoint.Y, Y2 = _secondpoint.Y };
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.DrawLine(_pen, (float)currentLine.X1, (float)currentLine.Y1, (float)currentLine.X2, (float)currentLine.Y2);
        g.Dispose();
        _mainCustomPictureBox.Invalidate();
        if (_previewCustomPictureBox != null && _previewCustomPictureBox.Image != null)
        {
            var gg = Graphics.FromImage(_previewCustomPictureBox.Image);
            gg.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            gg.DrawLine(_pen, (float)currentLine.X1, (float)currentLine.Y1, (float)currentLine.X2, (float)currentLine.Y2);
            gg.Dispose();
            _previewCustomPictureBox.Invalidate();
        }
        _firstpoint = _mainCustomPictureBox.PointToClient(new System.Drawing.Point(X, Y));

    }

Have you any idea, how to force UI of second window to refresh after every point?

Hawex

GuidoG
  • 11,359
  • 6
  • 44
  • 79
Hawex
  • 133
  • 13
  • 2
    In which event are you updating image to the second form? – Aleksa Ristic Oct 08 '18 at 07:43
  • can you also show the code where you update the second image – GuidoG Oct 08 '18 at 07:46
  • 1
    Sidenote, I recommend writing `using()` for any disposable object – GuidoG Oct 08 '18 at 07:48
  • Updating the second image is in this code, look into if (_previewCustomPictureBox != null && _previewCustomPictureBox.Image != null){..} I did it in the same way as adding lines to 1st. image – Hawex Oct 08 '18 at 08:08
  • Why it is not live? You invalidate both picboxes the same time. Do I miss anything? – γηράσκω δ' αεί πολλά διδασκόμε Oct 08 '18 at 08:19
  • I think this is caused by that second picturebox is in other window - 1st windows blocks ui thread of second window until 1st window stop drawing new lines (I'm drawing 200 short lines per second). – Hawex Oct 08 '18 at 08:34
  • 2
    You are not drawing *just* 200 lines per second but 200 images/sec per picbox! There is a big difference. Where do you call `AddNewPoint` from? Show the rest of your drawing code. – γηράσκω δ' αεί πολλά διδασκόμε Oct 08 '18 at 08:43
  • Add new point is called from event catched by WintabAPI (https://github.com/vvvv/WintabDN) private void MyWTPacketEventHandler(Object sender_I, MessageReceivedEventArgs eventArgs_I) { if (_wtData == null) return; WintabPacket pkt = _wtData.GetDataPacket((uint)eventArgs_I.Message.LParam, (uint)eventArgs_I.Message.WParam); if (pkt.pkNormalPressure > 0) { AddNewPoint(pkt.pkX, pkt.pkY, pkt.pkTime); } } Is there any way to format code in comment? – Hawex Oct 08 '18 at 08:47
  • I've also tried to draw directly on control, but doing it this way creates lot of problems (scalling lines), and also control in not giving live preview – Hawex Oct 08 '18 at 08:52
  • If the lines are connected you need to use DrawLines not DrawLine! – TaW Oct 08 '18 at 09:11
  • I'm using DrawLine, because I know only two points in moment of drawing - I'm not redrawing previous lines. – Hawex Oct 08 '18 at 09:27
  • 1
    Try to use this: https://stackoverflow.com/questions/50948912/best-way-to-write-thousands-of-strokes-in-wpf-canvas – Bartek Chyży Oct 08 '18 at 10:20
  • Thanks for this solution, unfotunately unsafe code ( *((int*)_bitmap.BackBuffer + offset) = Red; ) throws System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.' when I'm writing. Have you any solution for this ? – Hawex Oct 08 '18 at 10:53
  • I don't know if you have solved this, anyway, this "live" feature can be easily achieved *injecting* one of the Forms (the one where the drawing takes place) with an instance of the *Mirror* Form. When the *Mirror* is injected, you can subscribe the `Paint` event of its *mirror* `PictureBox` control and then `Invalidate()` the *mirror* in the exact same way. This will draw the same exact shapes in the two `PictureBoxes`. – Jimi Oct 08 '18 at 14:07

0 Answers0