“Перекрестный распараллельте операцию не допустимое” исключение на внутренних средствах управления

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

- (void)showOurAppsInAppStore
{        
    NSString *searchUrl = nil;
    // iPad
    if ([DeviceController isDeviceAnIpad]) {
        searchUrl = @"itms-apps://itunes.apple.com/us/artist/seligman-ventures-ltd/id326161338";
    }
    // iPhone / iPod Touch
    else {
        // iOS 7+
        if ([DeviceController isDeviceOperatingSystemAtleast:@"7.0"]) {
            searchUrl = @"itms-apps://itunes.apple.com/artist/seligman-ventures-ltd/id326161338";
        }
        // iOS 6
        else if ([DeviceController isDeviceOperatingSystemAtleast:@"6.0"]) {
            searchUrl = @"itms-apps://ax.itunes.apple.com/artist/seligman-ventures-ltd/id326161338";
        }
        // Pre iOS 6
        else {
            NSString *companyName = @"Seligman Ventures";
            searchUrl = [NSString stringWithFormat:@"http://phobos.apple.com/WebObjects/MZSearch.woa/wa/search?WOURLEncoding=ISO8859_1&lang=1&output=lm&country=US&term=%@&media=software", [companyName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        }
    }

    [[UIApplication sharedApplication] openURL: [NSURL URLWithString:searchUrl]];
}
7
задан johnc 8 July 2010 в 07:42
поделиться

7 ответов

В стороне - чтобы избежать необходимости создавать бесчисленные типы делегатов:

if (panel.InvokeRequired)
{
    panel.Invoke((MethodInvoker) delegate { AddControlToPanel(panel,ctrl); } );
    return;
}

Кроме того, теперь выполняется регулярная статическая проверка внутреннего вызова AddControlToPanel , так что вы не пойму неправильно.

3
ответ дан 6 December 2019 в 21:18
поделиться

Где создается pnlFoo и в каком потоке? Вы знаете, когда создается его дескриптор? Проблема в том, что он создается в исходном (не UI) потоке

. Все управляющие дескрипторы в одном окне должны быть созданы и доступны в одном потоке. На этом этапе вам не потребуется две проверки, требуется ли Invoke, потому что ctrl и панель должны использовать один и тот же поток.

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

3
ответ дан 6 December 2019 в 21:18
поделиться

Вот рабочий фрагмент кода:

public delegate void AddControlToPanelDlg(Panel p, Control c);

        private void AddControlToPanel(Panel p, Control c)
        {
            p.Controls.Add(c);
        }

        private void AddNewContol(object state)
        {
            object[] param = (object[])state;
            Panel p = (Panel)param[0];
            Control c = (Control)param[1]
            if (p.InvokeRequired)
            {
                p.Invoke(new AddControlToPanelDlg(AddControlToPanel), p, c);
            }
            else
            {
                AddControlToPanel(p, c);
            }
        }

А вот как я это тестировал. У вас должна быть форма с 2 кнопками и одним flowLayoutPanel (я выбрал это, чтобы мне не приходилось заботиться о местоположении h при динамическом добавлении элементов управления на панели)

private void button1_Click(object sender, EventArgs e)
        {
            AddNewContol(new object[]{flowLayoutPanel1, CreateButton(DateTime.Now.Ticks.ToString())});
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(AddNewContol), new object[] { flowLayoutPanel1, CreateButton(DateTime.Now.Ticks.ToString()) });
        }

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

1
ответ дан 6 December 2019 в 21:18
поделиться

«панель» и «ctrl» должны быть созданы в одном потоке, т.е. у вас не может быть panel.InvokeRequired, возвращающего значение, отличное от ctrl.InvokeRequired. То есть , если и панель, и ctrl создали дескрипторы или принадлежат контейнеру с созданным дескриптором . Из MSDN :

Если дескриптор элемента управления еще не существует, InvokeRequired выполняет поиск по родительская цепочка элемента управления, пока не найдет элемент управления или форма, у которой есть оконная ручка. Если нет подходящего ручку можно найти, Метод InvokeRequired возвращает false.

На данный момент ваш код открыт для условий гонки , потому что панель .InvokeNeeded может вернуть false, потому что панель еще не создана, тогда ctrl.InvokeNeeded обязательно вернет false, потому что, скорее всего, ctrl еще не добавлен ни в один контейнер, а затем, когда вы достигнете panel.Controls.Add , панель была создана в основном потоке, поэтому вызов не будет выполнен.

3
ответ дан 6 December 2019 в 21:18
поделиться

В вашем собственном ответе вы указываете:

Чтобы прояснить ситуацию: «панель» создается в базовом потоке, а «ctrl» - в новом потоке

Я думаю, что это может быть причина вашей проблемы. Все элементы UI должны быть созданы в одном потоке (базовом). Если вам нужно создать «ctrl» как следствие какого-либо действия в новом потоке, затем вызовите событие обратно в базовый поток и выполните создание там.

1
ответ дан 6 December 2019 в 21:18
поделиться

Вот небольшой фрагмент полной программы:

public class ucFoo : UserControl
{
    private Panel pnlFoo = new Panel();

    public ucFoo()
    {
        this.Controls.Add(pnlFoo);
    }
}

public class ucFoo2 : UserControl
{
    private Panel pnlFooContainer = new Panel();

    public ucFoo2()
    {
         this.Controls.Add(pnlFooContainer);
         Thread t = new Thread(new ThreadStart(AddFooControlToFooConatiner());
         t.Start()
    }

    private AddFooControlToFooConatiner()
    {
         ucFoo foo = new ucFoo();
         this.pnlFooContainer.Controls.Add(ucFoo); //<-- this is where the exception is raised
    }
}
0
ответ дан 6 December 2019 в 21:18
поделиться

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

.
1
ответ дан 6 December 2019 в 21:18
поделиться
Другие вопросы по тегам:

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