0

I have a form set as the IsMdiContainer attribute to true.

I'm trying to make it in the container "snows".

I am trying to adapt a code that works well on a normal WinForms, but not good on MDI container. This is what I managed to do:

public partial class SnowTest : Form
{

    int num;
    int[] x;
    int[] y;
    int[] v;
    int[] s;
    Random random = new Random();
    System.Drawing.Graphics graphics;
    Rectangle rectangle;
    private MdiClient MDIContainer;
    private Graphics asd;

    public SnowTest()
    {
        InitializeComponent();
    }

    private void SnowTest_Load(object sender, EventArgs e)
    {
        SelectMdiContainer();
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.UpdateStyles();
        snow();
        Timer1.Start();
    }

    private void SelectMdiContainer()
    {
        foreach (Control control in this.Controls)
        {

            // #2
            MdiClient client = control as MdiClient;
            if (!(client == null))
            {
                MDIContainer = client;
                break;
            }

        }
    }

    private void snow()
    {
        num = 2000;
        x = new int[num];
        y = new int[num];
        v = new int[num];
        s = new int[num];
        int i = 0;
        for (i = 0; i <= num - 1; i++)
        {
            Insnow(i);
        }
    }
    private void Insnow(int i)
    {
        x[i] = random.Next(0, this.Width - 1);
        y[i] = random.Next(0, this.Height * 5 / 7);
        v[i] = random.Next(5, 20);
        s[i] = (random.Next(1, 3) * 100 + random.Next(50, 200)) / 100;
    }

    private void Timer1_Tick(object sender, EventArgs e)
    {
        for (int i = 0; i <= num - 1; i++)
        {
            y[i] = y[i] + v[i];
            if (y[i] >= this.Height)
            {
                Insnow(i);
            }
        }
        Invalidate();
        SnowOnContainer();
    }

    private void SnowOnContainer()
    {
        graphics = MDIContainer.CreateGraphics();;
        int i = 0;
        for (i = 0; i <= num - 1; i++)
        {
            graphics.FillEllipse(Brushes.White, x[i], y[i], s[i], s[i]);
        }
    }

    private void SnowTest_Resize(object sender, EventArgs e)
    {
        rectangle = new Rectangle(0, 0, this.Width, this.Height);
    }
}

The Timer1 is set with a Interval of 100

The script runs and generates the "snow" but it does not remove it after a while and also the whole form creates lag.

What is the best way to achieve my goal?


In the normal form is pretty much structured in the same way, it lacks the function that select the container (SelectMdiContainer()), the function SnowOnContainer() and the global variable MDIContainer.

In the form, however, there is the paint event and consequently below carry as structured

private void SnowTest_Paint(object sender, PaintEventArgs e)
{
        graphics = e.Graphics;
        int i = 0;
        for (i = 0; i <= num - 1; i++)
        {
            graphics.FillEllipse(Brushes.White, x[i], y[i], s[i], s[i]);
        }
 }

EDIT

I'm doing some tests. Currently I removed the function SnowOnContainer() and added the Paint event for the container.

private void SelectMdiContainer()
{
        foreach (Control control in this.Controls)
        {

            // #2
            MdiClient client = control as MdiClient;
            if (!(client == null))
            {
                MDIContainer = client;
                MDIContainer.Paint += OnMdiContainerPaint; //Added this Event
                break;
            }
        }
 }

The event is structured as that of the normal form but applied to the container

private void OnMdiContainerPaint(object sender, PaintEventArgs e)
{
        graphics = MDIContainer.CreateGraphics();
        int i = 0;
        for (i = 0; i <= num - 1; i++)
        {
            graphics.FillEllipse(Brushes.White, x[i], y[i], s[i], s[i]);
        }
 }

Finally I did some research and I've added this code to avoid Flickering animation. as shown in this topic How to fix the flickering in User controls

protected override CreateParams CreateParams
{
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
            return cp;
        }
 }

In doing so it appears to be working properly with a fluid animation, but as soon as I resize the form, or I reduce to an icon returns lag

Community
  • 1
  • 1
Lorenzo Belfanti
  • 1,205
  • 3
  • 25
  • 51
  • To remove the "snow", in your `Timer1_Tick` event you need to change `Invalidate()` to `MDIContainer.Invalidate()`; now, about the lag: how often does your timer tick? can you post what are the differences between the code that works well on a normal winform? – Josh Part Dec 22 '16 at 16:57
  • @JoshPart I added as required differences with the normal form, the timer is repeated every 100 ms. I also tried to add as you were saying the `MDIContainer.Invalidate()` but this way you remove the snow but there is no longer the effect of falling snow – Lorenzo Belfanti Dec 23 '16 at 07:47
  • @JoshPart Now I tried to create the paint event for the MDI it seems to turn slightly better but the animation of the fall of snow is not as fluid as there is flicker, also there is always lag. it is as if you can not handle the animation on another thread – Lorenzo Belfanti Dec 23 '16 at 07:54

0 Answers0