Mám metodu ve třídě Form1 která na základě stisknutí tlačítka vytvoří vlákno druhé metody ve stejné třídě, která vykonává nějaký činný kód a podle výsledků zpracování zavolá další metodu která nastaví třeba popisky tlačítek atp. Problém je v tom, že program zkompiluji, ale spadne právě při pokusu upravit ty ovládací prvky. Zkoušel jsem k prvkům přistupovat přes Form1.JmenoPrvku.Text, nebo this.JmenoPrvku.Text, jenže přes Form1 to ani nezkompiluji (An object reference is required for the non-static field, method, or property 'CSSCon.Form1.BConnect') a přes this to spadne za běhu. Jak mám tedy přistupovat k ovládacím prvkům?
Fórum › .NET
[C#] Přístup k ovládacím prvkům z jiné metody
Tak já radši dám kousky zdrojáků. Tlačítka kterých se to týká mají Modifiers nastavený na Public a stejně když je zkouším upravit tak to padá. Jinak, BConnect je tlačítko, TAdress je textové pole pro IP adresu, TStatus je popisek ve stavové liště, program padne na řádku (zde) 15
private void ChangeState(uint Type, String Args)
{
// Status čekání na akci
//
if (Type == S_READY)
{
this.BConnect.Text = "Připojit";
this.BConnect.Enabled = true;
}
// Status přpojování
//
else if (Type == S_CONNECTING)
{
this.BConnect.Text = "Připojuji";
this.BConnect.Enabled = false;
this.TStatus.Text = Args;
}
// Status připojen
//
else if (Type == S_CONNECTED)
{
this.BConnect.Text = "Obnovit";
this.BConnect.Enabled = true;
this.TStatus.Text = "Odezva: " + Args;
}
// Status chyba
//
else
{
this.BConnect.Text = "Připojit";
this.BConnect.Enabled = true;
this.TStatus.Text = Args;
}
}
private void BConnect_Click(object sender, EventArgs e)
{
Thread tPing = new Thread(Ping);
tPing.IsBackground = true;
tPing.Start(TAdress.Text);
// TODO: Ukončení a opětovný start vlákna
//
}
private void Ping(object IAdress)
{
// Převod objektu na string
String Adress = (string)IAdress;
// Pokračování za předpokladu vyplněné adresy
//
if (Adress != "")
{
while (true)
{
this.ChangeState(S_CONNECTING, "Připojuji se k serveru");
String[] CIpHost = Adress.Split(':');
String CIp = CIpHost[0];
Int16 CPort = Convert.ToInt16(CIpHost[1]);
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 500;
PingReply reply = pingSender.Send(CIp, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
//MessageBox.Show(Convert.ToString(reply.RoundtripTime));
this.ChangeState(S_CONNECTED, Convert.ToString(reply.RoundtripTime) + "ms");
}
else
{
this.ChangeState(S_CONNECTED, "Timeout");
}
Thread.Sleep(500);
}
}
// Není vyplněna IP adresa
//
else
{
this.ChangeState(S_ERROR, "Vyplňte prosím IP adresu");
}
}
I toto jsem zkoušel, ale nakonec mi bylo řečeno, ať využiji následující metodu, která dovolí text u tláčítka změnit. U ostatních prvků, zrovna v mém případě text ve stavovém řádku, skutečně stačilo this.TStatus.Text = Args, u tlačítka jsem musel použít ChangeText(this.Tlacitko, "Text"); a teď ten kód.
public void ChangeText(Control ctrl, String value)
{
if (ctrl.InvokeRequired)
ctrl.Invoke((MethodInvoker)delegate() { ctrl.Text = value; });
else
ctrl.Text = value;
}
Já jsem měl možná podobný problém při práci se sériovým portem - událost při přijetí dat na portu vytvoří nové vlákno a nešlo mi vypsat do textboxu "data přijata". Při pokusu o změnu textu za běhu programu mi vypsalo něco o nepovoleném přístupu k prvku z vlákna, ve kterém nebyl vytvořen. Tak jsem hledal a našel jsem si:
delegate void SetTextCallback(Control ctrl, String text);
private void SetText(Control ctrl, String text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (ctrl.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { ctrl, text });
}
else
{
ctrl.Text = text;
}
}
V programu potom metodu volám následovně:
SetText(textBox1, "Ahoj světe");
Nevím, jestli ti to pomůže, protože jsem nestudoval tvůj kód do podrobností, ale mě to pomohlo. Dá se to upravit i pro nastavení jiných vlastností jiných prvků, podmínkou je přítomnost vlastnosti InvokeRequired.
Pro nejjednodussi pochopeni je dobrej tenhle priklad, je to ten nejjednodussi bezpecnej zpusob:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
private const int s = 12;
Thread mujThread = null;
delegate void mujDelegat(string text);//delegat pro pristup k textboxu
delegate void mujDelegatListBox(string[] text);//pro pristup k listboxu
public void startFce()//jenom spousteci fce, musi byt bezparametricka, nesmi byt static
{
this.vykonnaFce("Nastaveno");//musi byt volana dalsi fce, aby mohl byt predan
//spousteci parametr
}
public Form1()
{
InitializeComponent();
}
private void vykonnaFce(string text)//tato fce uz opravdu neco dela
{
if (this.textBox1.InvokeRequired)//pokud je volano z jineho threadu
//zabezpeci bezpecny pristup ke komponente,
//dale bude vykonan blok else
{
mujDelegat d = new mujDelegat(vykonnaFce);//vlakno si vytvori vlastniho delegata
this.Invoke(d, new object[] { text });
}
else//sem se pise kod, CO SE MA UDELAT !!!!!!!
{
this.textBox1.Text = text;
}
}
private void startFceListBox()//pocatecni fce pro listbox
{
string[] pole = new string[] {"1","2"};
this.vykonnaFceListBox(pole);
}
private void vykonnaFceListBox(string [] text)//vykonna fce pro listbox
{
if (this.pridejListBoxButton.InvokeRequired)//zabezpeci bezpecny pristup k listboxu
{
string[] pole = text ;
mujDelegatListBox d = new mujDelegatListBox(this.vykonnaFceListBox);
this.Invoke(d, new object[] { pole });
}
else//sem opet kod, co se ma vykonat
{
foreach (string i in text)
this.listBox1.Items.Add(i);
}
}
private void nastavTextBoxButton_Click(object sender, EventArgs e)
{
this.mujThread = new Thread(new ThreadStart(this.startFce));
this.mujThread.Start();
}
private void pridejListBoxButton_Click(object sender, EventArgs e)
{
this.mujThread = new Thread(new ThreadStart(startFceListBox));
this.mujThread.Start();
}
}
}
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
WinForm aplikace, přístup k ovládacím prvkům. — založil Tomáš Stejskal
Přístup k prvkům — založil TnTSkill
Přístup k prvkům objektu — založil survik1
Přístup k prvkum v 3D nafukujicim ArrayListu — založil Tedd
Moderátoři diskuze