Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка Windows Forms > ошибка при обращении к форме из другого потока


Автор: Demokratizator 12.9.2007, 14:23
Добрый день.
Не пойму в чем дело:
Ситуация - 
основной поток создает объект формы, но не запускае ее:
Код

Form1 _form = new Form1();


потом запускает второй поток, который запускае эту форму:
 
Код

System.Threading.Thread thread = new System.Threading.Thread(
            new System.Threading.ThreadStart(this.ThreadProc));

 thread.IsBackground = true;
 thread.Start();

 System.Threading.WaitHandle.WaitAll(new System.Threading.WaitHandle[] { this.WaitHandle });


private void ThreadProc()
{
             Application.Run(_logonForm);
}


во втором потоке открывается форма, и в ней есть процедура которая должна отработать в еще одном независимом процессе (3 поток получается)

так вот если в 3 потоке происходит ошибка, то срабатывает исключение

Код

 errorDialog.ShowDialog(frmMain.AcForm);

собственно ошибка: что обращение к AcForm не из потока порадившего ее.


frmMain - основная форма программы. запускается из main.
доступ к form1 такой:

Код

public static Form AcForm
{
            get{   return  GetForm1(); }
}


public delegate Form GetFormDelegate();
private Form _GetForm1()
{
      return _logonForm;
 }

public Form GetForm1()
{
               if (_form1.InvokeRequired)
                    return (Form)_form1.Invoke(new GetFormDelegate(this._GetForm1));
                else
                    return this._form1;

}


почему вылетает ошибка? причем это только если из 3 потока, если 3 поток убрать и подвесить form1 при выполнении кода, прежназначенного для 3 потока, то все гуд.
В чем трабла?
Спасибо. 

Автор: iad 12.9.2007, 15:34
Цитата(Demokratizator @  12.9.2007,  15:23 Найти цитируемый пост)
В чем трабла?
 сам же себе и ответил:
Цитата(Demokratizator @  12.9.2007,  15:23 Найти цитируемый пост)
обращение к AcForm не из потока порадившего ее.
 

Автор: Demokratizator 12.9.2007, 16:29
да, только вроде через Invoke все проходит...

Автор: iad 12.9.2007, 18:49
Цитата(Demokratizator @  12.9.2007,  17:29 Найти цитируемый пост)
да, только вроде через Invoke все проходит
Насколько я понимаю через инвоке у тебя только получение ссылки на _logonForm...имхо бессмысленно. Через инвоке нужно делать вызов errorDialog.ShowDialog(frmMain.AcForm); Из приведенного отрывочного кода сложновато понять.. 

Автор: zaver 12.9.2007, 18:58
кинь весь код и скажи где, когда и какая ошибка вылетает

Автор: Demokratizator 13.9.2007, 18:31
Основной файл программы

Код

private static LogonForm.LogonFormHelper _lfHelper = new  Estylesoft.LPS.LogonForm.LogonFormHelper();

static void Main() 
{
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledExceptionRaise);
     Application.ThreadException += new ThreadExceptionEventHandler(OnApplicationThreadExceptionRaise);
           
     try
     {
            _lfHelper.Show();
            if (_lfHelper.CanClose)
                   return;

            Application.Run(_mainForm = new frmMain());
      }
      catch (Exception ex)
     {
             Estylesoft.LPS.BusinessObjects.Errors.ShowError(ex);
      }
}

public static Form LogonForm
{
       get
       {
             if (_lfHelper != null)
                 return _lfHelper.Form;
             return null;
        }
}


файл LogonFormHelper
Код

public class LogonFormHelper
{
        public void Show()
        {
            //Запускаем другой поток, а основной ждет!
            System.Threading.Thread thread = new System.Threading.Thread(
                new System.Threading.ThreadStart(this.ThreadProc));

            thread.IsBackground = true;
            thread.Start();

            System.Threading.WaitHandle.WaitAll(new System.Threading.WaitHandle[] { this.WaitHandle });
        }

        public System.Threading.WaitHandle WaitHandle
        {
            get { return _logonForm.userIdentification; }
        }

        private void ThreadProc()
        {
             Application.Run(_logonForm);
        }

        public LogonBackground Form
        {
            get
            {
                if (_logonForm.InvokeRequired)
                    return (LogonBackground)_logonForm.Invoke(new GetFormDelegate(this.GetForm));
                else
                    return this._logonForm;
            }
        }

        private LogonBackground GetForm()
        {
            return _logonForm;
        }

        public delegate Form GetFormDelegate();
        private LogonBackground _logonForm = new LogonBackground();
}


файл LogonBackground

Код

public partial class LogonBackground : Form
{
        
        Logon frmLogon = null;

        public System.Threading.ManualResetEvent userIdentification = new System.Threading.ManualResetEvent(false);

        public LogonBackground()
       {
            InitializeComponent();
        }

        private void LogonBackground_Load(object sender, EventArgs e)
        {
            frmLogon = new Logon();
            frmLogon.buttonEnter.Click += new EventHandler(buttonEnter_Click);
            frmLogon.ButtonClose.Click += new EventHandler(buttonClose_Click);
            frmLogon.Show(this);
        }

        public void buttonEnter_Click(object sender, EventArgs e)
        {
            this.frmLogon.Cursor = Cursors.WaitCursor;
          
            Thread thread = new Thread(new ThreadStart(this.ThreadProc));
            thread.IsBackground = true;
            thread.Start();
        }

        private void ThreadProc()
        {
            try
            {
                   ТУТ КОД ВЫЗЫВАЕТ ОШИБКУ!
               
            }
            catch (Exception ex)
            {
                Errors.ShowError((ex != null ? ex : new Exception("Some error occur. Unmanaged exception was throwed by system.")));
                return;
            }
            
               ЕСЛИ ВСЕ ОК, ТО ОТПУСКАЕМ ОСНОВНОЙ ПОТОК 
             this.userIdentification.Set();
        }
}


файл Error

Код

 public static void ShowError(Exception ex)
        {
            ErrorDialog errorDialog = new ErrorDialog();
            
            Form parentForm = frmMain.LogonForm;
            
            if (parentForm == null)
                parentForm = (frmMain.ActiveForm != null ? frmMain.ActiveForm : frmMain.MainForm);
            
            if (parentForm != null)
            {
                Cursor cursor = parentForm.Cursor;
                
ВОТ ТУТ И ВЫЛЕЗАЕТ ОШИБКА: Cross-thread operation not valid: Control 'LogonBackground' accessed from a thread other than the thread it was created on.
                errorDialog.ShowDialog(parentForm);

                Application.DoEvents();
                parentForm.Cursor = cursor;
            }
        }

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