C# Много поточная обработка - Перемещение возражает между потоками

я работаю с управлением winforms, которое является и элементом GUI и также делает некоторую внутреннюю обработку, которая не была выставлена разработчику. То, когда этот компонент инстанцируют, он может взять между 5 и 15 секундами для становления готовым поэтому, что я хочу сделать, помещается это на другом потоке и когда ее сделанные возвращают его потоку gui и помещают его в мою форму. Проблема состоит в том, что это будет (и иметь), вызывают перекрестное исключение потока.

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

Кто-либо знает, возможно ли это и раз так как? Если не, как каждый имеет дело с проблемой как это, где существует потенциал для блокировки основного gui?

9
задан Grant 1 June 2010 в 12:36
поделиться

4 ответа

Класс BackgroundWorker предназначен именно для этой ситуации. Он будет управлять потоком за вас и позволит вам запустить поток, а также отменить поток. Поток может отправлять события обратно в поток графического интерфейса пользователя для обновления статуса или завершения. Обработчики событий для этих событий состояния и завершения находятся в основном потоке графического интерфейса пользователя и могут обновлять элементы управления WinForm. И WinForm не блокируется. Это все, что вам нужно. (И одинаково хорошо работает в WPF и Silverlight.)

0
ответ дан 3 November 2019 в 07:46
поделиться

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

Чтобы пользовательский интерфейс оставался отзывчивым при длительной инициализации, держите процесс в фоновом потоке и вызывайте любой доступ к элементам управления. Пользовательский интерфейс должен оставаться отзывчивым, но если это не так, вы можете добавить некоторое время ожидания в фоновый поток. Вот пример, использующий параллельные средства .Net 4: http://www.lovethedot.net/2009/01/parallel-programming-in-net-40-and_30.html

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

0
ответ дан 3 November 2019 в 07:46
поделиться

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

Элементы управления в Windows Forms привязаны к конкретный поток и не являются потоком безопасно. Поэтому, если вы звоните метод управления из другого поток, вы должны использовать один из методы вызова элемента управления для маршалинга вызов нужного потока. Этот свойство можно использовать, чтобы определить, вы должны вызвать метод вызова, который может быть полезно, если вы не знаете, что поток владеет элементом управления. ref

Вот как это выглядит в коде:

public delegate void ComponentReadyDelegate(YourComponent component);
public void LoadComponent(YourComponent component)
{
    if (this.InvokeRequired)
    {
        ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
        this.BeginInvoke(e, new object[]{component});
    }
    else
    {
        // The component is used by a UI control
        component.DoSomething();
        component.GetSomething();
    }
}

// From the other thread just initialize the component
// and call the LoadComponent method on the GUI.
component.Initialize(); // 5-15 seconds
yourForm.LoadComponent(component);

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

InvokeRequired сообщает вам, если:

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

Обновление:
Итак, если я правильно вас понял, объект управления создается в потоке, отличном от потока графического интерфейса, поэтому, даже если вы смогли передать его потоку графического интерфейса, вы все равно не сможете иметь возможность использовать его, не вызывая исключения между потоками. Решением было бы создать объект в потоке графического интерфейса пользователя, но инициализировать его в отдельном потоке:

public partial class MyForm : Form
{
    public delegate void ComponentReadyDelegate(YourComponent component);
    private YourComponent  _component;
    public MyForm()
    {
        InitializeComponent();
        // The componet is created on the same thread as the GUI
        _component = new YourComponent();

        ThreadPool.QueueUserWorkItem(o =>
        {
            // The initialization takes 5-10 seconds
            // so just initialize the component in separate thread
            _component.Initialize();

            LoadComponent(_component);
        });
    }

    public void LoadComponent(YourComponent component)
    {
        if (this.InvokeRequired)
        {
            ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
            this.BeginInvoke(e, new object[]{component});
        }
        else
        {
            // The component is used by a UI control
            component.DoSomething();
            component.GetSomething();
        }
    }
}
3
ответ дан 3 November 2019 в 07:46
поделиться

Не зная слишком многого об объекте. Чтобы избежать межпотоковых исключений, можно сделать так, чтобы начальный поток вызывал вызов (Даже если вы вызываете из потока).

Скопировано и вставлено из одного из моих собственных приложений:

 private delegate void UpdateStatusBoxDel(string status);

    private void UpdateStatusBox(string status)
    {
        listBoxStats.Items.Add(status);
        listBoxStats.SelectedIndex = listBoxStats.Items.Count - 1;
        labelSuccessful.Text = SuccessfulSubmits.ToString();
        labelFailed.Text = FailedSubmits.ToString();
    }

    private void UpdateStatusBoxAsync(string status)
    {
        if(!areWeStopping)
            this.BeginInvoke(new UpdateStatusBoxDel(UpdateStatusBox), status);
    }

Итак, по существу, задача с потоком вызовет метод "Async". Который затем скажет главной форме начать выполнение (фактически сам async).

Я считаю, что, вероятно, существует более короткий способ сделать все это, без необходимости создания делегатов и двух различных методов. Но этот способ просто укоренился во мне. И это то, что книги Microsoft учат делать :p

1
ответ дан 3 November 2019 в 07:46
поделиться
Другие вопросы по тегам:

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