Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Trouble Updating Controls From Within a While Loop

Posted on 2004-08-12
3
155 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

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
SSRS subreport with parameter 3 47
Sent email using Shared Mailbox from outlook in C# 5 50
Hey!!!! 1 25
Please explain purpose of GZIP 4 34
Introduction This article series is supposed to shed some light on the use of IDisposable and objects that inherit from it. In essence, a more apt title for this article would be: using (IDisposable) {}. I’m just not sure how many people would ge…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

856 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