Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Доступ к контролам в другом потоке


Автор: ДобренькийПапаша 18.3.2010, 10:55
Так получилось, что с многопоточностью работать не приходилось.
В одном классе есть две функции. Из одной происходит вызов второй, в которой надо открыть поток и получать доступ к нескольким элементам управления. А то я получаю исключение всё время,  мол "Недопустимая операция в нескольких потоках: попытка доступа к элементу управления 'такому-то' не из того потока, в котором он был создан."

Я быстро пролистал тему многопоточности, потыкался, но что-то пока не получается. А мне надо срочно решить эту проблему.

Автор: Voyager 18.3.2010, 11:04
Control.InvokeRequired
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx

Автор: A5uKa 18.3.2010, 11:10
Код

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern GetFocus() : IntPtr;
 
    [DllImport("user32.dll")]
    public static extern GetForegroundWindow() : IntPtr;
 
    [DllImport("user32.dll")]
    public static extern SetForegroundWindow(hWnd : IntPtr) : IntPtr;
 
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern PostMessage(hWnd : IntPtr,Msg : int,wParam : char,lParam : int) : bool;
 
    [DllImport("user32")]
    public static extern AttachThreadInput(idAttach : uint,idAttachTo : uint,fAttach : bool) : bool;
 
    [DllImport("user32")]
    public static extern GetWindowThreadProcessId(hWnd : IntPtr,lpdwProcessId : out uint) : uint;
 
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern GetCurrentThreadId() : uint;


... ?

п.с. но его Invoke лучше )

Автор: ДобренькийПапаша 18.3.2010, 12:19
Спасибо. Но до меня никак не допрёт...

Код

private void bWordExport_Click(object sender, EventArgs e)
        {
            WordExport();    //Этот метод нужно открыть в новом потоке...
        }
private void WordExport()
        {
             //что-то происходит
            int term = int.Parse(cbTerm.Text[0].ToString()); //Вот здесь из-за обращения к cbTerm.Text исключение
            //что-то дальше происходит
        }


Я не пойму как использовать тут InvokeRequired, а затем Invoke() с делегатом, в который надо засунуть метод и из него вернуть каким-то образом значение текстбокса, чтобы присвоить его переменной term. Как это сделать с BackgroundWorker тоже не пойму)))

Я чисто не могу представить себе конструкцию.

Автор: KelTron 18.3.2010, 13:04
Что то типа:
Код

private void WordExport()
        {
             //что-то происходит
            int term; 
            Invoke(new Action(() => term = int.Parse(cbTerm.Text[0].ToString())));
            //что-то дальше происходит
        }

Автор: Rohoss 18.3.2010, 20:51
ДобренькийПапаша, простите, но я чего то не понимаю... Насколько я знаю, контроллы должны быть в основном потоке. Если это так, то с доступом к контроллу не должно быть особых проблем. Не опйму, зачем в таком случаи импортировать "user32.dll"?  Хотя, если это WPF, то там решается немножко по другому. А если у вас контроллы в разных потоках (это вообще возможно?), то у вас как минимум ошибка в проектировании. 

Автор: ДобренькийПапаша 27.4.2010, 15:37
Снова открою тему, так получилось, что мне пришлось запускать метод асинхронно:

Код

 private void StartParsing()
        {
            //ParseCall - делегат
            ParseCall parseCall = ParseFileToLineChart;
            IAsyncResult iftAr = parseCall.BeginInvoke(null, null);
            parseCall.EndInvoke(iftAr);

            currentChart.Series[0].Points.DataBindXY(x, y);   
        }
private void ParseFileToLineChart()
        {
            this.x.Clear();
            this.y.Clear();

            if (currentChart.InvokeRequired) //Здесь выполнение "застревает"
            {
                Invoke(new Action(() => currentChart.Series[0].ChartType = SeriesChartType.Line));
            }
            
            //Ещё много кода...
        }


До этого я метод ParseFileToLineChart() запускал синхронно с помощью класса Thread, тогда внутри метода конструкция
Код

            if (currentChart.InvokeRequired) //Здесь выполнение "застревает"
            {
                Invoke(new Action(() => currentChart.Series[0].ChartType = SeriesChartType.Line));
            }


работала нормально. А теперь выполнение на этом месте "застревает". 

Заменил Invoke(...) на BeginInvok():
Код

            if (currentChart.InvokeRequired) //Так всё нормально!
            {
                BeginInvoke(new Action(() => currentChart.Series[0].ChartType = SeriesChartType.Line));
            }


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

Автор: ДобренькийПапаша 27.4.2010, 18:36
Таки нет. Неприятности остаются. В потоке, который запускаю через делегат, присутствуют несколько BeginInvoke() (в блоках InvokeRequired). Из-за особенностей асинхронного исполнения (как я понял), у меня в неправильной последовательности (для меня неправильной\некорректной с точки зрения логики) выполняются инструкции. Можно ли как-то управлять этим процессом? То есть завершить определённые действия в блоке InvokeRequired, чтобы выполнение шло дальше только после выполнения инструкций в блоке InvokeRequired.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)