c # ошибка перекрестного потока - PullRequest
0 голосов
/ 05 июня 2018

Я написал программу, которая сохраняет 3 разных положения моего датчика.Я хочу, чтобы фоновый цвет моих текстовых полей был зеленым, если датчик вернулся в сохраненную позицию.Поскольку значения меняются очень быстро и точно, я решил просто сравнить первые 3 значения.Итак, я запустил свою программу и сохранил позицию, нажав.Позиция сохранена, и текстовые поля сразу зеленые, что хорошо, потому что датчик все еще находится в этой позиции.Но после этого я получаю исключение для кросс-потоков и не понимаю этого.Я новичок в C #, и я думаю, что я решил эту проблему с помощью вызовов в начале моей функции.

        private void Safe_Position1(TextBox tBr1, TextBox tBi1, TextBox tBj1, TextBox tBk1, string[] text)
    {
        if (button3clicked == true)
        {
            if (!Dispatcher.CheckAccess())
            {
                textBox5.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }
            if (!Dispatcher.CheckAccess())
            {
                textBox7.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }
            if (!Dispatcher.CheckAccess())
            {
                textBox8.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }
            if (!Dispatcher.CheckAccess())
            {
                textBox9.Dispatcher.BeginInvoke(new Action(() => Safe_Position1(tBr1, tBi1, tBj1, tBk1, text)));
            }

            else
            {
                tBr1.Text = text[0];
                tBi1.Text = text[1];
                tBj1.Text = text[2];
                tBk1.Text = text[3];
                button3clicked = false;
            }

            string firstthreetBr1 = new string(text[0].Take(3).ToArray());
            string firstthreetBi1 = new string(text[1].Take(3).ToArray());
            string firstthreetBj1 = new string(text[2].Take(3).ToArray());
            string firstthreetBk1 = new string(text[3].Take(3).ToArray());


            if (firstthreetBr1 == tBr1.Text.Substring(0,3)) <------ EXCEPTION HERE
            {
                tBr1.Background = Brushes.Green;
            }
            if (firstthreetBi1 == tBi1.Text.Substring(0, 3))
            {
                tBi1.Background = Brushes.Green;
            }
            if (firstthreetBj1 == tBj1.Text.Substring(0, 3))
            {
                tBj1.Background = Brushes.Green;
            }
            if (firstthreetBk1 == tBk1.Text.Substring(0, 3))
            {
                tBk1.Background = Brushes.Green;
            }
        }
    }

Может кто-нибудь объяснить мне это?

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Я сделал похожую (не ту же ситуацию - вы должны понимать, не копировать, вставить) ситуацию для вас.

при нажатии кнопки я создаю 3 потока, которые обновляют текст в текстовых полях (которые были созданы в потоке пользовательского интерфейса))

private void btnStart_Click(object sender, EventArgs e)
{
    Thread t1 = new Thread(() => ThreadRunner(1));
    Thread t2 = new Thread(() => ThreadRunner(2));
    Thread t3 = new Thread(() => ThreadRunner(3));
    t1.Start();
    t2.Start();
    t3.Start();
}
private void ThreadRunner(int threadNum)
{
    while(true)
    {
        TextBoxUpdater(threadNum);
        Thread.Sleep(100 * threadNum);
    }
}

и метод, который вызывается для обновления текстовых полей,

private void TextBoxUpdater(int num)
{
    //here i m checking, if it is from different thread then UI thread
    //if yes then Invoke is used, 
    //      so it will call the same method but in UI thread
    if(this.InvokeRequired)
    {
        txtBox1.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox2.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox3.BeginInvoke(new Action(() => TextBoxUpdater(num)));
    }
    else
    {
        //If it is UI thread (meaning this call is coming from If part of this method)
        //and as it is UI thread now, we can update textbox's text
        txtBox1.Text = num.ToString();
        txtBox2.Text = num.ToString();
        txtBox3.Text = num.ToString();
    }

    //but after all above checks, we are leving below code without any checking
    //so once if part of this code will call this function again and else part of code runs
    // and then after completing that call, 
    //      flow will retun back to if part (not that it is not UI thread), 
    //      then flow will directly checks below codition and throw an exception
    if (txtBox1.Text.Substring(1) == "1")
    {

    }
}

с минимальными изменениями, которые вы можете сделать, как показано ниже, чтобы предотвратить исключение.

private void TextBoxUpdater(int num)
{
    //here i m checking, if it is from different thread then UI thread
    //if yes then Invoke is used, 
    //      so it will call the same method but in UI thread
    if(this.InvokeRequired)
    {
        txtBox1.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox2.BeginInvoke(new Action(() => TextBoxUpdater(num)));
        txtBox3.BeginInvoke(new Action(() => TextBoxUpdater(num)));
    }
    else
    {
        //If it is UI thread (meaning this call is coming from If part of this method)
        //and as it is UI thread now, we can update textbox's text
        txtBox1.Text = num.ToString();
        txtBox2.Text = num.ToString();
        txtBox3.Text = num.ToString();

        //perform this logic too insdie of else block
        if (txtBox1.Text.Substring(1) == "1")
        {
        }
    }
}

Но тогда и ваш метод вызовет слишком много ненужных вызовов TextBoxUpdater. Вы должны задаться вопросом, почему я это заявляю.

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

private void TextBoxUpdater(int num)
{
    if (this.InvokeRequired)
    {
        //if current call is form other than UI thread invoke to UI thread
        this.BeginInvoke(new Action(() => TextBoxUpdater(num)));
    }
    else
    {
        //If it is UI thread (meaning this call is coming from If part of this method)
        //and as it is UI thread now, we can update textbox's text
        txtBox1.Text = num.ToString();
        txtBox2.Text = num.ToString();
        txtBox3.Text = num.ToString();
        if (txtBox1.Text.Substring(1) == "1")
        {

        }
    }
}
0 голосов
/ 05 июня 2018

Как прокомментировал Мэтью, вы должны писать оператор возврата после каждого BeginInvoke ().Этот код вызывает исключение, потому что после того, как Ваш метод возвращается из BeginInvoke (), он углубляется в код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...