Ссылка на объект требуется для метода нестатического поля, или инициализатор свойства / поля не может ссылаться на метод или свойство нестатического поля
Я делал программу и наткнулся на эту проблему "два в одном", где первая проблема приводит к другой. Я еще не нашел вопрос, где у кого-то были обе проблемы, ведущие друг к другу. Я все еще учусь и многому научился от других проблем, которые у меня были, но я не могу найти решение этой проблемы.
Это связано с потоками. Я хочу создать поток, который может помещать что-то в расширенное текстовое поле каждую секунду или около того, в то время как я все еще могу нажимать кнопки для запуска и остановки. Но чтобы сделать функцию, которую может запустить поток, мне нужно сделать функцию статической. В противном случае я получу ошибку "Инициализатор поля не может ссылаться на нестатическое поле, метод или свойство". Но когда функция статическая, она не может получить доступ ни к одному из созданных элементов, например к richTextBox1. Потому что, если я пытаюсь изменить его текст, я получаю ошибку "Ошибка 1 Ссылка на объект требуется для нестатического поля, метода или свойства". И если я исправлю это путем удаления статики, поток не будет работать.
Я сделал демонстрационную программу, которая меньше полной, но имеет ту же проблему. Button1 - это кнопка для запуска потока, а Button2 - для его остановки.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace threading_non_static_problem_demo
{
public partial class Form1 : Form
{
static Thread thr = new Thread(new ThreadStart(demofunc));
int checkthr = 0; //int to check if the thread has been running before (I like to do things like this)
int ifthrrun = 0; //int to check if the thread is running
public Form1()
{
InitializeComponent();
button2.Enabled = false; // so you can't click the "stop" button if nothing is running
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
}
static void demofunc()
{
while (true)
{
Thread.Sleep(1000);
richTextBox1.Text = richTextBox1.Text + "text added"; // <-- here's the problem
MessageBox.Show("tried to add text"); // you can use this messagebox to check if the thread is working correctly
}
}
private void button1_Click(object sender, EventArgs e)
{
if (checkthr == 0) // check if the thread has run before, 0 is no, 1 is yes, and then start or resume it
{
thr.Start();
ifthrrun = 1;
button2.Enabled = true;
button1.Enabled = false;
}
else if (checkthr == 1)
{
thr.Resume();
ifthrrun = 1;
button2.Enabled = true;
button1.Enabled = false;
}
}
private void button2_Click(object sender, EventArgs e)
{
thr.Suspend();
checkthr = 1;
ifthrrun = 0;
button2.Enabled = false;
button1.Enabled = true;
}
protected override void OnFormClosing(FormClosingEventArgs e) // if the program is closing, check the thread's state and act accordingly
{
if (ifthrrun == 0)
{
if (checkthr == 1)
{
thr.Resume();
thr.Abort();
}
else if (checkthr == 0)
{
}
}
else if (ifthrrun == 1)
{
thr.Abort();
}
}
}
}
Чтобы использовать этот код, просто создайте приложение форм, добавьте две кнопки и поле с расширенным текстом, оно должно работать.
Заранее благодарю за ответы.
1 ответ
Но чтобы сделать функцию, которую может запустить поток, мне нужно сделать функцию статической.
Избавиться от static
объявления и перенести инициализацию вашей переменной "thr" в конструктор следующим образом:
Thread thr;
public Form1()
{
InitializeComponent();
button2.Enabled = false; // so you can't click the "stop" button if nothing is running
thr = new Thread(new ThreadStart(demofunc));
Control.CheckForIllegalCrossThreadCalls = false;
}
private void demofunc()
{
while (true)
{
Thread.Sleep(1000);
richTextBox1.Text = richTextBox1.Text + "text added"; // <-- problem "solved" by disabling Control.CheckForIllegalCrossThreadCalls
}
}
Но игнорируйте приведенное выше "исправление", потому что использование Suspend()/Resume() не рекомендуется.
См. Приостановка и возобновление потоков:
Важный
Начиная с версии.NET Framework 2.0, методы Thread.Suspend и Thread.Resume помечаются как устаревшие и будут удалены в следующем выпуске.
Методы Thread.Suspend и Thread.Resume, как правило, бесполезны для приложений и их не следует путать с механизмами синхронизации. Поскольку Thread.Suspend и Thread.Resume не зависят от взаимодействия контролируемого потока, они очень навязчивы и могут привести к серьезным проблемам приложения, таким как взаимоблокировки (например, если вы приостановите поток, содержащий ресурс, который будет создан другим потоком) необходимость).
Один из способов сделать паузу / возобновить ваш цикл - это использовать ManualResetEvent следующим образом:
Thread thr;
ManualResetEvent mre = new ManualResetEvent(false);
public Form1()
{
InitializeComponent();
button2.Enabled = false; // so you can't click the "stop" button if nothing is running
thr = new Thread(new ThreadStart(demofunc));
}
private void demofunc()
{
while (!this.IsDisposed && !this.Disposing)
{
Thread.Sleep(1000);
if (!this.IsDisposed && !this.Disposing)
{
this.Invoke((MethodInvoker)delegate {
richTextBox1.AppendText("text added");
});
}
mre.WaitOne();
}
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
mre.Set();
if (!thr.IsAlive)
{
thr.Start();
}
button2.Enabled = true;
}
private void button2_Click(object sender, EventArgs e)
{
button2.Enabled = false;
mre.Reset();
button1.Enabled = true;
}
protected override void OnFormClosing(FormClosingEventArgs e) // if the program is closing, check the thread's state and act accordingly
{
mre.Set(); // make sure the loop continues so it can drop out
}
}