Threads, textboxes and scrolling

W

Wesman

Threads, textboxes and scrolling

Thanks in advance for any information on this matter. I have run into
a small richtextbox, scrolling and tread issue. Which has me totally
confused. Instead of trying to explain it I wrote some small C# code
to demonstrate the fact that in the threaded version the textbox
simple doesn't scroll like it should… please look to the
startButton_Click method for the distinction between the two
programs..

Thanks

Wesley

why does this work ?????????????


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

namespace Test
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Test : System.Windows.Forms.Form
{
const string newline = "\r\n";

/// <summary>
/// Required designer variable.
/// </summary>

private System.Windows.Forms.Button startButton;
private System.Windows.Forms.RichTextBox output;
private System.ComponentModel.Container components = null;

public Test()
{
InitializeComponent();
}

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

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

#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.startButton = new System.Windows.Forms.Button();
this.output = new System.Windows.Forms.RichTextBox();
this.SuspendLayout();
//
// startButton
//
this.startButton.Anchor = (System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Right);
this.startButton.Location = new System.Drawing.Point(424, 8);
this.startButton.Name = "startButton";
this.startButton.TabIndex = 0;
this.startButton.Text = "Start";
this.startButton.Click += new
System.EventHandler(this.startButton_Click);
//
// output
//
this.output.Anchor = (((System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right);
this.output.Location = new System.Drawing.Point(0, 40);
this.output.Name = "output";
this.output.Size = new System.Drawing.Size(512, 296);
this.output.TabIndex = 1;
this.output.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(512, 334);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.output,
this.startButton});
this.Name = "Form1";
this.Text = "Backup Utility";
this.ResumeLayout(false);

}
#endregion



/// <summary>
/// this method takes the giving string and writes it to the
richtextbox.
/// this method appends a new line at the end of the input string to
facilite
/// returns and scrolling to the botton.. callers need not add a
newline.
/// </summary>
/// <param name="msg">string</param>
private void DisplayNewEvent(string msg)
{
output.AppendText(msg + newline);
output.Focus();
output.SelectionStart = output.Text.Length + 1;
output.SelectionLength = 0;
output.ScrollToCaret();
}

private void startButton_Click(object sender, System.EventArgs e)
{
GoThroughMyDocuments();
}

/// <summary>
/// this functions goes through all the folders and files and places
the
/// filename in the richtext box...
/// </summary>
private void GoThroughMyDocuments()
{
DirectoryInfo info = new DirectoryInfo(
@"C:\Documents and Settings\" +
SystemInformation.UserName +
@"\My Documents");

RecursivelyTransverseFilesAndFolders(info.GetDirectories());
GetFileName(info.GetFiles());
}

//recursively find all the files in all directories in "My
Documents"
private void RecursivelyTransverseFilesAndFolders(DirectoryInfo[]
directories)
{
if(directories!=null)
foreach(DirectoryInfo dir in directories)
{
RecursivelyTransverseFilesAndFolders(dir.GetDirectories());
GetFileName(dir.GetFiles());
}
}

// get each file name and print its full path to the text box
private void GetFileName(FileInfo[] info)
{
if(info!=null)
foreach(FileInfo file in info)
DisplayNewEvent(file.FullName);
}
}
}


and this not work??????????

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

namespace ThreadTest
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class ThreadTest : System.Windows.Forms.Form
{
const string newline = "\r\n";

Thread worker1;


/// <summary>
/// Required designer variable.
/// </summary>

private System.Windows.Forms.Button startButton;
private System.Windows.Forms.RichTextBox output;
private System.ComponentModel.Container components = null;

public ThreadTest()
{
InitializeComponent();
}

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

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

#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.startButton = new System.Windows.Forms.Button();
this.output = new System.Windows.Forms.RichTextBox();
this.SuspendLayout();
//
// startButton
//
this.startButton.Anchor = (System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Right);
this.startButton.Location = new System.Drawing.Point(424, 8);
this.startButton.Name = "startButton";
this.startButton.TabIndex = 0;
this.startButton.Text = "Start";
this.startButton.Click += new
System.EventHandler(this.startButton_Click);
//
// output
//
this.output.Anchor = (((System.Windows.Forms.AnchorStyles.Top |
System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right);
this.output.Location = new System.Drawing.Point(0, 40);
this.output.Name = "output";
this.output.Size = new System.Drawing.Size(512, 296);
this.output.TabIndex = 1;
this.output.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(512, 334);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.output,
this.startButton});
this.Name = "Form1";
this.Text = "Backup Utility";
this.ResumeLayout(false);

}
#endregion



/// <summary>
/// this method takes the giving string and writes it to the
richtextbox.
/// this method appends a new line at the end of the input string to
facilite
/// returns and scrolling to the botton.. callers need not add a
newline.
/// </summary>
/// <param name="msg">string</param>
private void DisplayNewEvent(string msg)
{
output.AppendText(msg + newline);
output.Focus();
output.SelectionStart = output.Text.Length + 1;
output.SelectionLength = 0;
output.ScrollToCaret();
}

private void startButton_Click(object sender, System.EventArgs e)
{
worker1 = new Thread(new ThreadStart(GoThroughMyDocuments));
worker1.Start();

// primary thread continues its execution while the worker goes
// throught its laborous task.
}

/// <summary>
/// this functions goes through all the folders and files and places
the
/// filename in the richtext box...
/// </summary>
private void GoThroughMyDocuments()
{
DirectoryInfo info = new DirectoryInfo(
@"C:\Documents and Settings\" +
SystemInformation.UserName +
@"\My Documents");

RecursivelyTransverseFilesAndFolders(info.GetDirectories());
GetFileName(info.GetFiles());
worker1.Abort();
}

//recursively find all the files in all directories in "My
Documents"
private void RecursivelyTransverseFilesAndFolders(DirectoryInfo[]
directories)
{
if(directories!=null)
foreach(DirectoryInfo dir in directories)
{
RecursivelyTransverseFilesAndFolders(dir.GetDirectories());
GetFileName(dir.GetFiles());
}
}

// get each file name and print its full path to the text box
private void GetFileName(FileInfo[] info)
{
if(info!=null)
foreach(FileInfo file in info)
DisplayNewEvent(file.FullName);
}
}
}
 
M

Michael Mayer

I hit the wrong "reply" button again. maybe it's time to change
newsreaders...

----- Original Message -----
From: "Wesman said:
Thanks in advance for any information on this matter. I have run into
a small richtextbox, scrolling and tread issue. Which has me totally
confused. Instead of trying to explain it I wrote some small C# code
to demonstrate the fact that in the threaded version the textbox
simple doesn't scroll like it should. please look to the
startButton_Click method for the distinction between the two
programs..


Well, the first thing I noticed in Form2 is that it appears you are trying
to update a UI from another thread. That is, you start a new thread with
the method:
GoThroughMyDocuments
that calls
GetFileName
which finally calls
DisplayNewEvent
This method works with the UI. However, it is not running on the same
thread as the UI (sometimes called the UI thread). Big no-no.

See this article for info:
http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading/default.aspx

Replace your GetFileName() with something like the following, and it seems
to work a lot better...

delegate void DisplayFilenameHandler (string text);

// get each file name and print its full path to the text box
private void GetFileName(FileInfo[] info)
{
DisplayFilenameHandler show = new DisplayFilenameHandler
(DisplayNewEvent);
if(info!=null)
foreach(FileInfo file in info)
{
output.Invoke (show, new object[] {file.FullName});
//DisplayNewEvent(file.FullName);
}
}

Additionally, i'd be tempted to add a cancel button. The above article
should give you some tips on doing that. I'd suggest inheriting from the
authors AsyncOperation class to create your "worker" class. Put all your
code in "DoWork" with checks for the canceled flag, and using his event
firing methods to assist with updating the UI.


Mike Mayer
http://www.mag37.com
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top