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

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

    [TestMethod]
    public void ShouldBeAbleToConvertAnAnonymousObjectToAnExpandoObject()
    {
        var additionalViewData = new {id = "myControlId", css = "hide well"};
        dynamic result = new ExpandoObject();
        var dict = (IDictionary<string, object>)result;
        foreach (PropertyInfo propertyInfo in additionalViewData.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            dict[propertyInfo.Name] = propertyInfo.GetValue(additionalViewData, null);
        }
        Assert.AreEqual(result.id, "myControlId");
        Assert.AreEqual(result.css, "hide well");
    }
542
задан Henk Holterman 30 July 2013 в 08:35
поделиться

6 ответов

Согласно комментарий обновления Prerak K (так как удаленный):

я предполагаю, что не представил вопрос правильно.

ситуация - это: Я хочу загрузить данные в глобальную переменную на основе значения управления. Я не хочу изменять значение управления от дочернего потока. Я не собираюсь делать это когда-либо от дочернего потока.

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

решение, которое Вы хотите тогда, должно быть похожим:

UserContrl1_LOadDataMethod()
{
    string name = "";
    if(textbox1.InvokeRequired)
    {
        textbox1.Invoke(new MethodInvoker(delegate { name = textbox1.text; }));
    }
    if(name == "MyName")
    {
        // do whatever
    }
}

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

UserContrl1_LOadDataMethod()
{
    if(textbox1.text=="MyName") //<<======Now it wont give exception**
    {
        //Load data correspondin to "MyName"
        //Populate a globale variable List<string> which will be
        //bound to grid at some later stage
        if(InvokeRequired)
        {
            // after we've done all the processing, 
            this.Invoke(new MethodInvoker(delegate {
                // load the control with the appropriate data
            }));
            return;
        }
    }
}
406
ответ дан Community 30 July 2013 в 08:35
поделиться

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

8
ответ дан Pat 30 July 2013 в 08:35
поделиться

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

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

17
ответ дан Peter Mortensen 30 July 2013 в 08:35
поделиться

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

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

72
ответ дан Jon Skeet 30 July 2013 в 08:35
поделиться

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

fsw.SynchronizingObject = this

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

41
ответ дан Druid 30 July 2013 в 08:35
поделиться

The cleanest (and proper) solution for UI cross-threading issues is to use SynchronizationContext, see Synchronizing calls to the UI in a multi-threaded application article, it explains it very nicely.

14
ответ дан 22 November 2019 в 22:16
поделиться
Другие вопросы по тегам:

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