Ссылка на объект требуется для метода нестатического поля, или инициализатор свойства / поля не может ссылаться на метод или свойство нестатического поля

Я делал программу и наткнулся на эту проблему "два в одном", где первая проблема приводит к другой. Я еще не нашел вопрос, где у кого-то были обе проблемы, ведущие друг к другу. Я все еще учусь и многому научился от других проблем, которые у меня были, но я не могу найти решение этой проблемы.

Это связано с потоками. Я хочу создать поток, который может помещать что-то в расширенное текстовое поле каждую секунду или около того, в то время как я все еще могу нажимать кнопки для запуска и остановки. Но чтобы сделать функцию, которую может запустить поток, мне нужно сделать функцию статической. В противном случае я получу ошибку "Инициализатор поля не может ссылаться на нестатическое поле, метод или свойство". Но когда функция статическая, она не может получить доступ ни к одному из созданных элементов, например к 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
    }

}
Другие вопросы по тегам