Avoiding creating PictureBoxes again and again

后端 未结 3 1276
栀梦
栀梦 2020-12-11 19:01

I\'ve got the following problem. My intention is to move several images from the right to the left in a Windows Form. The code below works quite fine. What bothers me is the

3条回答
  •  猫巷女王i
    2020-12-11 19:58

    This isn't directly an answer to this question - I think that's primarily because of all the Bitmap images you're creating. You should only create one and then the problem goes away.

    What I'm suggesting here is an alternative way of coding this that cuts the code enormously.

    All of my code goes straight in your Background constructor after the line this.MaximizeBox = false;. Everything after that is removed.

    So start with loading the image:

    var image = new Bitmap(@"C:\MyPath\Sky.jpg");
    

    Next, work out how many picture boxes do I need to tile the image across the form based on the width and height passed in:

    var countX = width / image.Width + 2;
    var countY = height / image.Height + 2;
    

    Now create the actual picture boxes that will populate the screen:

    var pictureBoxData =
    (
        from x in Enumerable.Range(0, countX)
        from y in Enumerable.Range(0, countY)
        let positionX = x * image.Width
        let positionY = y * image.Height
        let pictureBox = new PictureBox()
        {
            Image = image,
            Location = new Point(positionX, positionY),
            Size = new Size(image.Width, image.Height),
        }
        select new
        {
            positionX,
            positionY,
            pictureBox,
        }
    ).ToList();
    

    Next, add them all to the Controls collection:

    pictureBoxData.ForEach(pbd => this.Controls.Add(pbd.pictureBox));
    

    Finally, use Microsoft's Reactive Framework (NuGet Rx-WinForms) to create a timer that will update the Left position of the picture boxes:

    var subscription =
        Observable
            .Generate(
                0,
                n => true,
                n => n >= image.Width ? 0 : n + 1,
                n => n,
                n => TimeSpan.FromMilliseconds(10.0))
            .ObserveOn(this)
            .Subscribe(n =>
            {
                pictureBoxData
                    .ForEach(pbd => pbd.pictureBox.Left = pbd.positionX - n);
            });
    

    Finally, before launching the dialog, we need a way to cleanup all of the above so that the form closes cleanly. Do this:

    var disposable = new CompositeDisposable(image, subscription);
    this.FormClosing += (s, e) => disposable.Dispose();
    

    Now you can do the ShowDialog:

    this.ShowDialog();
    

    And that's it.

    Apart from nugetting Rx-WinForms, you need to add the following using statements to the top of the code:

    using System.Reactive.Linq;
    using System.Reactive.Disposables;
    

    It all worked nicely for me:

    dialog

提交回复
热议问题