WinForms, эквивалентный executeSelectorOnMainThread в Objective-C - PullRequest
1 голос
/ 17 марта 2010

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

data.ImportProgressChanged += new 
     DataAccess.ImportDelegate(data_ImportProgressChanged);

Thread importThread = new Thread(
       new ThreadStart(data.ImportPeopleFromFAD));
importThread.IsBackground = true;
importThread.Start();

void data_ImportProgressChanged(int progress)
{
    toolStripProgressBar.Value = progress;
}

//In my data object I have 
public void ImportPeopleFromFAD()
{
    ImportProgressChanged(someInt);
}

Но пользовательский интерфейс не обновляется, поскольку вызов ImportProgressChanged() выполняется в фоновом потоке. В цели C я знаю, что вы можете использовать executeSelectorOnMainThread и передать ему метод для вызова с использованием основного потока. Каков эквивалентный способ вызова ImportProgressChanged() из основного потока?

Ответы [ 3 ]

2 голосов
/ 17 марта 2010

(Предполагая Windows Forms.) Вы можете использовать Control.Invoke или Control.BeginInvoke - но более чистый способ может использовать BackgroundWorker для начала.

В WPF вы бы использовали Dispatcher вместо Control.Invoke, кстати. См. Это Руководство по резьбовой модели WPF для получения более подробной информации.

РЕДАКТИРОВАТЬ: Лично я, вероятно, не стал бы сначала проверять InvokeRequired - я бы просто позвонил Invoke или BeginInvoke. Если вы уже на правильном пути, это не принесет существенного вреда.

Тем не менее, для индикаторов прогресса BackgroundWorker - определенно путь вперед.

1 голос
/ 17 марта 2010

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

Самое короткое изменение заключается в использовании Control.InvokeRequired и .Invoke (), но Backgroundworker был специально создан для этого сценария.

Если вы хотите решить это в объекте данных, вы должны сделать так, чтобы это зависело от графического интерфейса, поэтому лучше решить это в обработчике:

void data_ImportProgressChanged(int progress)
{
    if (toolStripProgressBar.InvokeRequired)
    {
        Action<int> a = new Action(data_ImportProgressChanged);
        toolStripProgressBar.Invoke(a, progress);
    }
    else
        toolStripProgressBar.Value = progress;
}
0 голосов
/ 19 марта 2010

У вас уже есть ответ, но я все равно добавлю свое решение:

void data_ImportProgressChanged(int progress)
{
    if (InvokeRequired)
    {
        BeginInvoke(new Action<int>(data_ImportProgressChanged),progress);
        return;
    }

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