Недопустимая операция с перекрестным потоком: ошибка асинхронных делегатов

#c#

#c#

Вопрос:

Я пытался изучить делегатов.Я только что создал кнопку, метку и флажок. Если я нажму флажок, формат времени изменится. Если я нажму на кнопку, я напечатаю соответствующую дату. Однако при попытке использовать асинхронный делегат, т. Е. Использовать другой поток, я застрял с ошибкой

    public delegate void AsyncDelegate(bool seconds);

public partial class Form1 : Form
{
    AsyncDelegate ad;
    TimeZ t = new TimeZ();
    public Form1()
    {
        InitializeComponent();
    }

 private void btn_async_Click(object sender, EventArgs e)
    {

        ad = new AsyncDelegate(t.GetTime);
        AsyncCallback acb = new AsyncCallback(CB);
        if (chk_sec.Checked)
        {
            ad.BeginInvoke(true, acb, null);
        }
        else
            ad.BeginInvoke(false, acb, null);


    }
    public void CB(IAsyncResult ar)
    {
        t.Tim = ar.ToString();
        ad.EndInvoke(ar);
        lbl_time.Text = t.Tim;
    }
 

и в другой библиотеке классов я получаю Timez, использованный выше. Я добавляю ссылку на нее в проект

  public class TimeZ
{
  private string tim;
    public string Tim
    {
        get
        {
            return tim;
        }
        set
        {
            tim = value;
        }
    }
    public string GetTime(bool seconds)
    {
        if (seconds)
        {
           return DateTime.Now.ToLongTimeString();
        }
        else
            return DateTime.Now.ToShortTimeString();
    }
}
 

Однако я получаю эту ошибку при запуске программы:

  Cross-thread operation not valid: Control 'lbl_time' accessed from a thread other than   
    the thread it was created on.
 

Можете ли вы помочь мне решить эту проблему?

Комментарии:

1. У меня в голове не укладывается, что кто-то может проголосовать за это. Что вы вообще пытаетесь сделать с этим кодом?

Ответ №1:

Вы не можете получить доступ к свойствам и методам форм и элементов управления из потока, который не является потоком формы.

В Windows каждое окно привязано к потоку, который его создал.

Вы можете сделать это только с помощью Control .BeginInvoke или более полезная система.Многопоточность.Класс SynchronizationContext.

См. http://msdn.microsoft.com/it-it/library/system.threading.synchronizationcontext (v= против 95).aspx

См. http://msdn.microsoft.com/it-it/library/0b1bf3y3 (v= против 80).aspx

Это означает, что вам нужно опубликовать через контекст синхронизации, например, другой асинхронный делегат в потоке формы.

 public partial class Form1 : Form
{
    AsyncDelegate ad;
    TimeZ t = new TimeZ();

    // Our synchronization context
    SynchronizationContext syncContext;

    public Form1()
    {
        InitializeComponent();

        // Initialize the synchronization context field
        syncContext = SynchronizationContext.Current;
    }

    private void btn_async_Click(object sender, EventArgs e)
    {

        ad = new AsyncDelegate(t.GetTime);
        AsyncCallback acb = new AsyncCallback(CB);
        if (chk_sec.Checked)
        {
            ad.BeginInvoke(true, acb, null);
        }
        else
        {
            ad.BeginInvoke(false, acb, null);
        }
    }

    public void CB(IAsyncResult ar)
    {
        // this will be executed in another thread
        t.Tim = ar.ToString(); // ar.ToString()???? this will not give you the time for sure! why?
        ad.EndInvoke(ar);

        syncContext.Post(delegate(object state)
        {
            // This will be executed again in form thread
            lbl_time.Text = t.Tim;
        }, null);
    }
 

Однако я не знаю, зачем вам нужен асинхронный обратный вызов для времени печати 🙂 на самом деле не знаю почему, думая, что это просто какой-то тестовый код.

Комментарии:

1. я не знаю, где я ошибаюсь, но теперь он выводит System.Remote. Удаленное подключение. Обмен сообщениями. Результат AsyncResult, а не текущая дата

2. Это означает, что он работает сейчас, но в вашем коде все еще есть что-то еще «неправильное». lbl_time. Текст = XXXXXX;