C # SharpDevelop DataGridView в Mainform.Designer.cs & hellip; хочу получить доступ в MainForm.cs, но получает & ldquo; ошибка поперечного потока & rdquo; [Дубликат]

Когда объекту класса Derived присвоен объект Base class Object, все члены объекта производного класса копируются в объект базового класса, за исключением членов, которых нет в базовом классе. Эти члены удаляются компилятором. Это называется Object Slicing.

Вот пример:

#include<bits/stdc++.h>
using namespace std;
class Base
{
    public:
        int a;
        int b;
        int c;
        Base()
        {
            a=10;
            b=20;
            c=30;
        }
};
class Derived : public Base
{
    public:
        int d;
        int e;
        Derived()
        {
            d=40;
            e=50;
        }
};
int main()
{
    Derived d;
    cout<<d.a<<"\n";
    cout<<d.b<<"\n";
    cout<<d.c<<"\n";
    cout<<d.d<<"\n";
    cout<<d.e<<"\n";


    Base b = d;
    cout<<b.a<<"\n";
    cout<<b.b<<"\n";
    cout<<b.c<<"\n";
    cout<<b.d<<"\n";
    cout<<b.e<<"\n";
    return 0;
}

Он будет генерировать:

[Error] 'class Base' has no member named 'd'
[Error] 'class Base' has no member named 'e'
473
задан Henk Holterman 30 July 2013 в 09:35
поделиться

18 ответов

Это не рекомендуемый способ решить эту ошибку, но вы можете быстро ее подавить, она выполнит эту работу. Я предпочитаю это для прототипов или демонстраций. добавьте

CheckForIllegalCrossThreadCalls = false

в конструкторе Form1().

4
ответ дан Özgür 21 August 2018 в 08:21
поделиться

Действие y; // объявлен внутри класса

label1.Invoke (y = () => label1.Text = "text");

0
ответ дан Antonio Leite 21 August 2018 в 08:21
поделиться

Вот альтернативный способ, если объект, с которым вы работаете, не имеет

(InvokeRequired)

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

delegate void updateMainFormObject(FormObjectType objectWithoutInvoke, string text);

private void updateFormObjectType(FormObjectType objectWithoutInvoke, string text)
{
    MainForm.Invoke(new updateMainFormObject(UpdateObject), objectWithoutInvoke, text);
}

public void UpdateObject(ToolStripStatusLabel objectWithoutInvoke, string text)
{
    objectWithoutInvoke.Text = text;
}

Он работает так же, как и выше, но это другой подход, если у вас нет объекта с invokerequired, но do имеют доступ к MainForm

3
ответ дан Ashitakalax 21 August 2018 в 08:21
поделиться

Я знаю его слишком поздно. Однако даже сегодня, если у вас возникли проблемы с доступом к элементам управления перекрестными потоками? Это самый короткий ответ до даты: P

Invoke(new Action(() =>
                {
                    label1.Text = "WooHoo!!!";
                }));

Вот как я обращаюсь к любому управлению формой из потока.

9
ответ дан Bravo 21 August 2018 в 08:21
поделиться

Модель Threading в UI

Пожалуйста, прочитайте Threading Model в приложениях пользовательского интерфейса, чтобы понять основные понятия. Ссылка перемещается на страницу, описывающую модель потоков WPF. Тем не менее, Windows Forms использует ту же идею.

Пользовательский интерфейс

  • Существует только один поток (поток пользовательского интерфейса), которому разрешен доступ к System.Windows .Forms.Control и его подклассы.
  • Попытайтесь получить доступ к члену System.Windows.Forms.Control из другого потока, кроме потока пользовательского интерфейса, вызовет перекрестный поток Исключение.
  • Поскольку существует только один поток, все операции пользовательского интерфейса помещаются в качестве рабочих элементов в этот поток:

enter image description here [/g22]

  • Если для потока пользовательского интерфейса нет работы, тогда существуют промежутки времени ожидания, которые могут использоваться вычислениями, не связанными с UI.
  • Для использования указанных недостатков используйте System .Windows.Forms.Control.Invoke или System.Windows.Forms.Control.BeginInvoke :

enter image description here [/g23]

Методы BeginInvoke и Invoke

  • Вычисление вычислительных ресурсов вызываемого метода должно быть небольшим, а также вычислить накладные расходы на методы обработчика событий, поскольку U Здесь используется поток I - тот же самый, который отвечает за обработку ввода пользователя. Независимо от того, является ли это System.Windows.Forms.Control.Invoke или System.Windows.Forms.Control.BeginInvoke .
  • Для выполнения вычисления дорогостоящей операции всегда используйте отдельный поток. Поскольку .NET 2.0 BackgroundWorker предназначен для выполнения дорогостоящих операций в Windows Forms. Однако в новых решениях вы должны использовать шаблон async-await, описанный здесь здесь .
  • Используйте System.Windows.Forms.Control.Invoke или System.Windows.Forms.Control.BeginInvoke только для обновления пользовательского интерфейса. Если вы используете их для тяжелых вычислений, ваше приложение заблокирует:

enter image description here [/g24]

Вызвать

enter image description here [/g25]

BeginInvoke

enter image description here [/g26]

Решение для кода

Прочитать ответы на вопрос Как обновить графический интерфейс из другого потока в C #? . Для C # 5.0 и .NET 4.5 рекомендуемым решением является здесь .

141
ответ дан Community 21 August 2018 в 08:21
поделиться
  • 1
    Ссылка msdn.microsoft.com/en-us/library/ms741870.aspx больше не работает. – Amadeus Sánchez 11 January 2016 в 20:52
  • 2
    будет control.BeginInvoke работать тоже? – newbieguy 11 December 2016 в 00:30
  • 3
    Прошло некоторое время с тех пор, как я сделал программирование на C #, но на основе статьи MSDN и моих неоднозначных знаний это похоже на это. – Jeff Hubbard 13 December 2016 в 22:17
  • 4
    Разница в том, что BeginInvoke () является асинхронным, а Invoke () работает синхронно. [Д0] stackoverflow.com/questions/229554/… – frzsombor 13 October 2017 в 00:18

В тех же строках, что и в предыдущих ответах, но очень короткое дополнение, которое позволяет использовать все свойства Control без исключения перекрестного потока invoke.

Метод помощника

/// <summary>
/// Helper method to determin if invoke required, if so will rerun method on correct thread.
/// if not do nothing.
/// </summary>
/// <param name="c">Control that might require invoking</param>
/// <param name="a">action to preform on control thread if so.</param>
/// <returns>true if invoke required</returns>
public bool ControlInvokeRequired(Control c, Action a)
{
    if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate
    {
        a();
    }));
    else return false;

    return true;
}

Образец Использование

// usage on textbox
public void UpdateTextBox1(String text)
{
    //Check if invoke requied if so return - as i will be recalled in correct thread
    if (ControlInvokeRequired(textBox1, () => UpdateTextBox1(text))) return;
    textBox1.Text = ellapsed;
}

//Or any control
public void UpdateControl(Color c, String s)
{
    //Check if invoke requied if so return - as i will be recalled in correct thread
    if (ControlInvokeRequired(myControl, () => UpdateControl(c, s))) return;
    myControl.Text = s;
    myControl.BackColor = c;
}
5
ответ дан cramopy 21 August 2018 в 08:21
поделиться

У меня была эта проблема с FileSystemWatcher и выяснилось, что следующий код решил проблему:

fsw.SynchronizingObject = this

Затем элемент управления использует текущий объект формы для решения с событиями, и поэтому будет в одной и той же теме.

36
ответ дан Druid 21 August 2018 в 08:21
поделиться
  • 1
    Да! и я был здесь pacifically для FileSystemWatcher – Valamas 10 September 2012 в 11:30
  • 2
    Это спасло мою бекон. В VB.NET я использовал .SynchronizingObject = Me – codingcoding 23 June 2016 в 02:40
this.Invoke(new MethodInvoker(delegate
            {
                //your code here;
            }));
2
ответ дан Hamid Jolany 21 August 2018 в 08:21
поделиться

Самое чистое (и правильное) решение для кросс-потоковых проблем UI - использовать SynchronizationContext, см. Синхронизация вызовов с пользовательским интерфейсом в статье с несколькими потоками , это очень хорошо объясняет.

10
ответ дан Igor Brejc 21 August 2018 в 08:21
поделиться

Новый взгляд с использованием Async / Await и callback. Вам нужна только одна строка кода, если вы сохраните метод расширения в своем проекте.

/// <summary>
/// A new way to use Tasks for Asynchronous calls
/// </summary>
public class Example
{
    /// <summary>
    /// No more delegates, background workers etc. just one line of code as shown below
    /// Note it is dependent on the XTask class shown next.
    /// </summary>
    public async void ExampleMethod()
    {
        //Still on GUI/Original Thread here
        //Do your updates before the next line of code
        await XTask.RunAsync(() =>
        {
            //Running an asynchronous task here
            //Cannot update GUI Thread here, but can do lots of work
        });
        //Can update GUI/Original thread on this line
    }
}

/// <summary>
/// A class containing extension methods for the Task class 
/// Put this file in folder named Extensions
/// Use prefix of X for the class it Extends
/// </summary>
public static class XTask
{
    /// <summary>
    /// RunAsync is an extension method that encapsulates the Task.Run using a callback
    /// </summary>
    /// <param name="Code">The caller is called back on the new Task (on a different thread)</param>
    /// <returns></returns>
    public async static Task RunAsync(Action Code)
    {
        await Task.Run(() =>
        {
            Code();
        });
        return;
    }
}

Вы можете добавить другие вещи к методу расширения, например, обернуть его в оператор Try / Catch, чтобы вызывающий мог сказать ему, какой тип будет возвращен после завершения, обратный вызов исключения для вызывающего:

Добавление Try Catch, Auto Exception Logging и CallBack

    /// <summary>
    /// Run Async
    /// </summary>
    /// <typeparam name="T">The type to return</typeparam>
    /// <param name="Code">The callback to the code</param>
    /// <param name="Error">The handled and logged exception if one occurs</param>
    /// <returns>The type expected as a competed task</returns>

    public async static Task<T> RunAsync<T>(Func<string,T> Code, Action<Exception> Error)
    {
       var done =  await Task<T>.Run(() =>
        {
            T result = default(T);
            try
            {
               result = Code("Code Here");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unhandled Exception: " + ex.Message);
                Console.WriteLine(ex.StackTrace);
                Error(ex);
            }
            return result;

        });
        return done;
    }
    public async void HowToUse()
    {
       //We now inject the type we want the async routine to return!
       var result =  await RunAsync<bool>((code) => {
           //write code here, all exceptions are logged via the wrapped try catch.
           //return what is needed
           return someBoolValue;
       }, 
       error => {

          //exceptions are already handled but are sent back here for further processing
       });
        if (result)
        {
            //we can now process the result because the code above awaited for the completion before
            //moving to this statement
        }
    }
6
ответ дан John Peters 21 August 2018 в 08:21
поделиться

Вы хотите использовать Invoke или BeginInvoke для минимальной части работы, необходимой для изменения пользовательского интерфейса. Ваш «тяжелый» метод должен выполняться в другом потоке (например, через BackgroundWorker), но затем с помощью Control.Invoke / Control.BeginInvoke только для обновления пользовательского интерфейса. Таким образом, ваш поток пользовательского интерфейса будет свободно обрабатывать события пользовательского интерфейса и т. Д.

См. Мою статью для потоковой передачи для примера WinForms - хотя статья была написана ранее BackgroundWorker прибыл на место происшествия, и, боюсь, я не обновил его в этом отношении. BackgroundWorker немного упрощает обратный вызов.

66
ответ дан Jon Skeet 21 August 2018 в 08:21
поделиться
  • 1
    здесь в этом моем состоянии. Я даже не изменяю интерфейс. Я просто получаю текущие значения из дочернего потока. любое предложение hw для реализации – Prerak K 26 September 2008 в 22:26
  • 2
    Вам все равно нужно перейти к потоку пользовательского интерфейса даже для доступа к свойствам. Если ваш метод не может продолжаться до тех пор, пока значение не будет доступно, вы можете использовать делегат, который возвращает значение. Но да, пройдите через поток пользовательского интерфейса. – Jon Skeet 26 September 2008 в 22:38
  • 3
    Привет, Джон, я верю, что ты направляешь меня в правильном направлении. Да, мне нужно значение без него, я не могу продолжить. Не могли бы вы рассказать о том, что «использование делегата, возвращающего значение». благодаря – Prerak K 26 September 2008 в 22:46
  • 4
    Используйте делегат, такой как Func & lt; string & gt ;: string text = textbox1.Invoke ((Func & lt; string & gt;) () = & gt; textbox1.Text); (Предполагается, что вы используете C # 3.0 - в противном случае вы могли бы использовать анонимный метод.) – Jon Skeet 26 September 2008 в 22:49

Существует два варианта операций с поперечными потоками.

Control.InvokeRequired Property 

, а второй - использовать

SynchronizationContext Post Method

Control.InvokeRequired полезен только при работе с элементами управления, унаследованными от Control класс, в то время как SynchronizationContext можно использовать в любом месте. Некоторая полезная информация относится к следующим ссылкам:

Пользовательский интерфейс Cross Thread Update | .Net

Пользовательский интерфейс Cross Thread Update с использованием SynchronizationContext | .Net

-1
ответ дан Nasir Mahmood 21 August 2018 в 08:21
поделиться

Тот же вопрос: How-to-update-the-gui-from-another-thread-in-c

Two Ways:

  1. Возвращаемое значение в e.result и использовать его для установки значения вашего текстового поля в backgroundWorker_RunWorkerCompleted event
  2. Объявить некоторую переменную для хранения этих значений в отдельном классе (который будет работать как держатель данных). Создайте статический экземпляр этого класса и вы можете получить к нему доступ по любому потоку.

Пример:

public  class data_holder_for_controls
{
    //it will hold value for your label
    public  string status = string.Empty;
}

class Demo
{
    public static  data_holder_for_controls d1 = new data_holder_for_controls();
    static void Main(string[] args)
    {
        ThreadStart ts = new ThreadStart(perform_logic);
        Thread t1 = new Thread(ts);
        t1.Start();
        t1.Join();
        //your_label.Text=d1.status; --- can access it from any thread 
    }

    public static void perform_logic()
    {
        //put some code here in this function
        for (int i = 0; i < 10; i++)
        {
            //statements here
        }
        //set result in status variable
        d1.status = "Task done";
    }
}
0
ответ дан o_O 21 August 2018 в 08:21
поделиться

Вам нужно посмотреть пример Backgroundworker: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx Особенно, как он взаимодействует с уровнем пользовательского интерфейса , Основываясь на вашей публикации, это, похоже, отвечает на ваши вопросы.

5
ответ дан Pat 21 August 2018 в 08:21
поделиться

Элементы управления в .NET не являются в общем потокобезопасными. Это означает, что вам не следует обращаться к элементу управления из потока, отличного от того, в котором он живет. Чтобы обойти это, вам нужно вызвать элемент управления, который пытается выполнить ваш второй образец.

Однако в вашем случае все, что вы сделали, - это передать длинный метод обратно в основной поток. Конечно, это не то, что вы хотите сделать. Вам нужно переосмыслить это немного, чтобы все, что вы делали в основном потоке, устанавливало быстрое свойство здесь и там.

13
ответ дан Peter Mortensen 21 August 2018 в 08:21
поделиться

Я нахожу код check-and-invoke, который должен быть усеян во всех методах, связанных с формами, слишком многословным и ненужным. Вот простой метод расширения, который позволяет полностью устранить его:

public static class Extensions
{
    public static void Invoke<TControlType>(this TControlType control, Action<TControlType> del) 
        where TControlType : Control
        {
            if (control.InvokeRequired)
                control.Invoke(new Action(() => del(control)));
            else
                del(control);
    }
}

И тогда вы можете просто сделать это:

textbox1.Invoke(t => t.Text = "A");

Больше не возиться - просто.

12
ответ дан Rob 21 August 2018 в 08:21
поделиться

Например, чтобы получить текст из элемента управления потоком пользовательского интерфейса:

Private Delegate Function GetControlTextInvoker(ByVal ctl As Control) As String

Private Function GetControlText(ByVal ctl As Control) As String
    Dim text As String

    If ctl.InvokeRequired Then
         text = CStr(ctl.Invoke(New GetControlTextInvoker(AddressOf GetControlText), _
                           ctl))
    Else
        text = ctl.Text
    End If

Return text
End Function
2
ответ дан UrsulRosu 21 August 2018 в 08:21
поделиться

Следуйте простейшему (на мой взгляд) способу изменения объектов из другого потока:

using System.Threading.Tasks;
using System.Threading;

namespace TESTE
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Action<string> DelegateTeste_ModifyText = THREAD_MOD;
            Invoke(DelegateTeste_ModifyText, "MODIFY BY THREAD");
        }

        private void THREAD_MOD(string teste)
        {
            textBox1.Text = teste;
        }
    }
}
6
ответ дан Vanderley Maia 21 August 2018 в 08:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: