Solved

Trouble Updating Controls From Within a While Loop

Posted on 2004-08-12
3
156 Views
Last Modified: 2010-04-15
I've written a function that is supposed to update a listbox and a label every time I iterate through a while loop. For some reason, the controls are not being updated. However, when I terminate the loop prematurely (with a return statement) both controls update correctly.

Is this typical behavior for a while loop, or is there something odd going on with the controls?
0
Comment
Question by:nh_capricorn
  • 2
3 Comments
 
LVL 2

Expert Comment

by:davidastle
ID: 11790277
To make a long story short, it has to with windows.  To force your controls to be shown as they truly are, call the Update() function on your window or on a control.

The weird behavior has to do with the way windows works.

Your application knows when to redraw itself because windows will send it a message called WM_PAINT.  The caveat is that windows will only send this message if your messages queue is empty, and when you are constantly changing controls in a while loop, your message queue is never empty.

It does not have to with while loops.   Lets say that you have an infinite loop that starts when you click on your window and updates your textbox.  To test to see if its doing anything, lets make it do something more than just update the text data.
Make sure your project properties are set so to console application to follow my code.

while (true)
{
    myTextBox.Text += "Foo";
    Console.WriteLine(myTextBox.Text);
}

If you run this, you will see that your text box data is in fact getting updated.  The reason why it is not displaying is because of windows!  Microsoft is not sending you WM_PAINT messages.  To prove this, lets track all the windows messages that are sent your app.  Make a new windows form project, and set it to console application.  Now, create a new class below your form class called MyFilter and make it inherit IMessageFilter.  This will be used to track the windows messages that are passed to your window.  Next, you have to add the filter when the application loads.  Here is an example that will start your loop when you click the mouse button.  It will show all the windows messages past in a console window:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication1
{
      /// <summary>
      /// Summary description for Form1.
      /// </summary>
      public class Form1 : System.Windows.Forms.Form
      {
            private System.Windows.Forms.TextBox textBox1;
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.Container components = null;

            public Form1()
            {
                  //
                  // Required for Windows Form Designer support
                  //
                  InitializeComponent();

                  //
                  // TODO: Add any constructor code after InitializeComponent call
                  //
                  this.Load +=new EventHandler(Form1_Load);
                  this.MouseDown +=new MouseEventHandler(Form1_MouseDown);
            }

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            protected override void Dispose( bool disposing )
            {
                  if( disposing )
                  {
                        if (components != null)
                        {
                              components.Dispose();
                        }
                  }
                  base.Dispose( disposing );
            }

            #region Windows Form Designer generated code
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                  this.textBox1 = new System.Windows.Forms.TextBox();
                  this.SuspendLayout();
                  //
                  // textBox1
                  //
                  this.textBox1.Location = new System.Drawing.Point(88, 112);
                  this.textBox1.Name = "textBox1";
                  this.textBox1.Size = new System.Drawing.Size(376, 20);
                  this.textBox1.TabIndex = 0;
                  this.textBox1.Text = "textBox1";
                  //
                  // Form1
                  //
                  this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
                  this.ClientSize = new System.Drawing.Size(600, 478);
                  this.Controls.Add(this.textBox1);
                  this.Name = "Form1";
                  this.Text = "Form1";
                  this.ResumeLayout(false);

            }
            #endregion

            /// <summary>
            /// The main entry point for the application.
            /// </summary>
      
            static void Main()
            {
                  Application.Run(new Form1());
            }

            private void Form1_Load(object sender, EventArgs e)
            {
                  Application.AddMessageFilter(new MyFilter());
            }

            private void Form1_MouseDown(object sender, MouseEventArgs e)
            {
                  while (true)
                  {
                        this.textBox1.Text += "A";
                        Console.WriteLine(this.textBox1.Text);
                  }
            }
      }
      public class MyFilter : IMessageFilter
      {
            #region IMessageFilter Members

            public bool PreFilterMessage(ref Message m)
            {
                  // TODO:  Add MyFilter.PreFilterMessage implementation
                  Console.WriteLine(m.Msg);
                  return false;
            }

            #endregion

      }

}

As you will see, windows stops sending messages once your loop starts, including the WM_PAINT message.  The reason why windows will not send the message is because your application message queue is never empty, and windows is waiting for it to be empty.  For more info on WM_PAINT, go to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_88ac.asp

If you call the Update() function on your control or form, it will force the window to be repainted.
0
 
LVL 2

Accepted Solution

by:
davidastle earned 300 total points
ID: 11790295
So instead of:
while (true)
{
   myTextBox.Text += "A";
}
Do:
while (true)
{
   myTextBox.Text += "A";
   myTextBox.Update();
}
You could also call the Update function on the current window (this.Update()).  This will automatically update every child control as well.
0
 

Author Comment

by:nh_capricorn
ID: 11800858
Thanks David!

I really appreciate all of the detail you put into your answer. Guess I'm just going to have to get used to programming with windows (Java was a lot simpler, IMO).

- nhc
0

Featured Post

Secure Your Active Directory - April 20, 2017

Active Directory plays a critical role in your company’s IT infrastructure and keeping it secure in today’s hacker-infested world is a must.
Microsoft published 300+ pages of guidance, but who has the time, money, and resources to implement? Register now to find an easier way.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question