How to resolve strange problem with DialogBox containing PictureBox?

Nicholas Piazza 536 Reputation points
2024-07-17T15:15:34.2766667+00:00

I have a Windows Forms application with a number of dialog boxes that are opened when clicking on a menu item. I recently added a new DialogBox called Sierpinski whose OnClick event handler is as follows:

    // Event handler for selecting the Sierpinski Triangle dialog box.
    private void OnClickSierpinski (object sender, EventArgs e)
    {
        var sierpinskiDialog = new Sierpinski ();
        SetTitleAndLocation (sierpinskiDialog, null);
        sierpinskiDialog.ShowDialog (this);
    }

The code for the DialogBox is shown below:


public partial class Sierpinski : Form
{
    Bitmap image;
    int x1 = 400, y1 = 10;
    int x2 = 800, y2 = 440;
    int x3 = 0, y3 = 440;
    int xn = 400, yn = 10;
    int plot;
    Color color = new ();
    Random random = new ();
    public Sierpinski ()
    {
        InitializeComponent ();
        DrawSierpinski ();
    }
    private void DrawSierpinski ()
    {
        image = new (800, 440, PixelFormat.Format24bppRgb);
        for (int i = 1; i <= 10000; i++)
        {
            plot = random.Next (3) + 1;
            switch (plot)
            {
                case 1:
                    xn = (xn + x1) / 2; yn = (yn + y1) / 2;
                    break;
                case 2:
                    xn = (xn + x2) / 2; yn = (yn + y2) / 2;
                    break;
                case 3:
                    xn = (xn + x3) / 2; yn = (yn + y3) / 2;
                    break;
            }
            color = Color.FromArgb (255 - i / 40, 0, i / 40);
            image.SetPixel (xn, yn, color);
        }
        //pictureBox1.Image = image;
        _ = Read ();
        image.Dispose ();
    }

Note that with the PictureBox line commented out, when I click the menu item the DialogBox is displayed, but of course, without an image. However, if I uncomment the PictureBox line, the DialogBox is not even displayed. Instead I get the following exception:

sOnClickBad

What's going on here? Why does adding the assignment of an image to the PictureBox.Image property prevent the DialogBox from displaying?

Windows
Windows
A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.
5,358 questions
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,821 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,879 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Viorel 116.8K Reputation points
    2024-07-17T15:31:48.75+00:00

    Do not dispose the image that is needed. Try this:

    . . .
    pictureBox1.Image?.Dispose( );
    pictureBox1.Image = image;
    //image.Dispose( ); REMOVED
    
    0 comments No comments

  2. Michael Taylor 54,221 Reputation points
    2024-07-17T15:40:29.6633333+00:00

    There are several problems with your code.

    Firstly you don't want to be doing that method call in the constructor. It'll mess everything up. Here's the problem. The constructor is called when you new the instance. So the line var sierpinskiDialog = new Sierpinski (); is what actually triggers a call to your Draw method. Notice that this is long before the UX is actually shown, if it is shown at all. The only thing you should be doing in your constructor is initializing the fields and setting up the control instances. Everything else should be deferred until the OnLoad method is called. This method is called after the UX is created but just before it is shown (generally by ShowDialog). It is at this point that you can do any final initialization of the UX before rendering.

    Why does this matter? It matters because of the designer. When you load your form in the designer of VS it has to create an instance of your form. To do that it has to create an instance (just like you're doing in code) and that requires running the constructor. So anything in your constructor is run in the designer as well as runtime. Now, as you make changes to the UX in the designer it is, behind the scenes, writing those changes to the InitializeComponent method. The designer is going to generate the same code that you would manually. The problem is that the designer cannot tell the difference between you making a change in the designer and your constructor calling methods that make changes. As far as the designer is concerned they are the same. So any methods you call in your constructor that adjust properties of the controls will ultimately get written to the InitializeComponent method. Hence your method logic is duplicated. Now this happens whenever the designer regenerates the code and not necessarily right away, but it will eventually happen. So either configure your code in the designer (and let it right out the code) or defer any additional changes until OnLoad so the designer doesn't generate the same code again.

    The second problem with your code is the scope of the image. You define image as a field. But you only use it in 1 method AND you cannot reuse that image because PictureBox explicitly states that the image you give it cannot be used elsewhere. So you need to move the definition of image into the method as a regular variable. This will prevent you from reusing it by accident.

    Now we're to the third problem which is the lifetime of the image instance. You create the instance, set up the image and assign it to the PictureBox. But then you dispose of the image which wipes it out. At the point you handed it to PictureBox then PictureBox is now responsible for the lifetime of the image. You cannot dispose of it because then you're disposing of the image that the control is trying to use. At that point it is going to crash.

    Resolve these problems and see if the issue goes away. If it still remains then there could be something wrong with the image format but a cursory glance doesn't indicate any issues. Post your updated code and we can take another look.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.