Peter Duniho said:
[...]
I get the error:
Cross-thread operation not valid: Control 'btnExit' accessed
from a thread other than the thread it was created on.
I am trying to find out how to access the controls on the Form from
either
the same class or a different class (which was why we were passing
"this" to
the other class).
This all works fine until you put it in a thread.
That's because you need to use Control.Invoke() or Control.BeginInvoke()
to execute the code that actually has to touch the control itself.
The other reply doesn't really address this. That reply is not a lot
different from your own attempt to solve the issue with a property, in
that it's just an alternate route to the same code, ultimately with the
same problem: it will try to interact with the control from a thread other
than the one that owns that control.
Without a concise-but-complete code sample to work with, it's difficult to
propose a precise change for your particular scenario. But, as an
example, you might modify your IStatusDisplay.Status property so that it
looks like this:
[snip]
Ok, here is a stripped down sample that consists of 3 buttons, a textbox,
statusbar and toolStripStatusLabel.
I have 2 files (form1 and Maintenance). In form1 I am calling a function in
Maintenance that just writes to the textbox and the toolStripStatusLabel.
The first button calls the function without a thread and the second with a
thread.
I also have a this.Refresh() in the code to display on the page correctly
when not running in the thread, but in the thread it gives me the error:
Cross-thread operation not valid: Control 'Form1' accessed from a thread
other than the thread it was created on.
If I comment it out, and run the threading, I get the following when the
program tries to write to the textbox (Status) from the Maintenance
function:
display.Status += file + Environment.NewLine;
Calls this to set the value
set
{
Status.Text = value;
}
And get the error:
Cross-thread operation not valid: Control 'Status' accessed from a
thread other than the thread it was created on.
but I don't get the error when setting the toolStripStatusLabel from the
Maintenance function:
display.StatusBar = "Now Processing... " + file;
Why is that? They are both using the "this" that was passed.
Just trying to understand the different ways to do this so I can choose the
right way in other situations as well.
The 3 files in my project are:
form1.cs
****************************************************
using System;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ControlAccessAcrossClasses
{
public partial class Form1 : Form, IStatusDisplay
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
toolStripStatusLabel1.Text = "This is a test";
}
#region IStatusDisplay Members
string IStatusDisplay.Status
{
get
{
return Status.Text;
}
set
{
Status.Text = value;
}
}
string IStatusDisplay.StatusBar
{
get
{
return toolStripStatusLabel1.Text;
}
set
{
toolStripStatusLabel1.Text = value;
//this.Refresh();
}
}
#endregion
private void WithoutThreadButton_Click(object sender, EventArgs e)
{
Maintenance.CheckAll(this);
}
private void WithThreadButton_Click(object sender, EventArgs e)
{
Thread oThread = new Thread(new ThreadStart(CallWithThread));
oThread.Start();
}
private void CallWithThread()
{
Maintenance.CheckAll(this);
}
private void Exit_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
}
***************************************************************
maintenance.cs
**************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ControlAccessAcrossClasses
{
class Maintenance
{
public static void CheckAll(IStatusDisplay display)
{
String file = "12345.txt";
display.StatusBar = "Now Processing... " + file;
display.Status += file + Environment.NewLine;
}
}
public interface IStatusDisplay
{
string Status { get; set; }
string StatusBar { get; set; }
}
}
**************************************************************
And the form1.designer.cs
*************************************************************
namespace ControlAccessAcrossClasses
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be
disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (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.Status = new System.Windows.Forms.TextBox();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel1 = new
System.Windows.Forms.ToolStripStatusLabel();
this.WithThreadButton = new System.Windows.Forms.Button();
this.WithoutThreadButton = new System.Windows.Forms.Button();
this.Exit = new System.Windows.Forms.Button();
this.statusStrip1.SuspendLayout();
this.SuspendLayout();
//
// Status
//
this.Status.Location = new System.Drawing.Point(30, 12);
this.Status.Multiline = true;
this.Status.Name = "Status";
this.Status.Size = new System.Drawing.Size(364, 286);
this.Status.TabIndex = 0;
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new
System.Windows.Forms.ToolStripItem[] {
this.toolStripStatusLabel1});
this.statusStrip1.Location = new System.Drawing.Point(0, 347);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(495, 22);
this.statusStrip1.TabIndex = 1;
this.statusStrip1.Text = "statusStrip1";
//
// toolStripStatusLabel1
//
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
this.toolStripStatusLabel1.Size = new System.Drawing.Size(0,
17);
//
// WithThreadButton
//
this.WithThreadButton.Location = new System.Drawing.Point(187,
316);
this.WithThreadButton.Name = "WithThreadButton";
this.WithThreadButton.Size = new System.Drawing.Size(90, 23);
this.WithThreadButton.TabIndex = 2;
this.WithThreadButton.Text = "With Thread";
this.WithThreadButton.UseVisualStyleBackColor = true;
this.WithThreadButton.Click += new
System.EventHandler(this.WithThreadButton_Click);
//
// WithoutThreadButton
//
this.WithoutThreadButton.Location = new System.Drawing.Point(30,
316);
this.WithoutThreadButton.Name = "WithoutThreadButton";
this.WithoutThreadButton.Size = new System.Drawing.Size(114,
23);
this.WithoutThreadButton.TabIndex = 3;
this.WithoutThreadButton.Text = "Without Thread";
this.WithoutThreadButton.UseVisualStyleBackColor = true;
this.WithoutThreadButton.Click += new
System.EventHandler(this.WithoutThreadButton_Click);
//
// Exit
//
this.Exit.Location = new System.Drawing.Point(318, 316);
this.Exit.Name = "Exit";
this.Exit.Size = new System.Drawing.Size(75, 23);
this.Exit.TabIndex = 4;
this.Exit.Text = "Exit";
this.Exit.UseVisualStyleBackColor = true;
this.Exit.Click += new System.EventHandler(this.Exit_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(495, 369);
this.Controls.Add(this.Exit);
this.Controls.Add(this.WithoutThreadButton);
this.Controls.Add(this.WithThreadButton);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.Status);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox Status;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel
toolStripStatusLabel1;
private System.Windows.Forms.ToolStripStatusLabel
toolStripStatusLabel2;
private System.Windows.Forms.Button WithThreadButton;
private System.Windows.Forms.Button WithoutThreadButton;
private System.Windows.Forms.Button Exit;
}
}
**************************************************************
Not sure why there are 2 "partial class form1" classes.
Thanks,
Tom