2009-09-02 3 views
1

Я пишу простую структуру для тестирования приложений WinForm, которые запущены в процессе. Я использую Application.OpenForms, чтобы найти элемент управления, который мне нужно изменить на текущем шаге. Тем не менее, иногда я получаю ошибки, связанные с изменением коллекции (возможно, некоторым другим потоком). Как заблокировать эту коллекцию, чтобы убедиться, что обычные потоки пользовательского интерфейса (открытие новых форм и т. Д.) Не мешают?Как заблокировать Application.OpenForms?

ответ

2

Я не думаю, что есть встроенное решение, чтобы зафиксировать это свойство. Я предлагаю не использовать foreach -loop, чтобы предотвратить исключение, вызванное тем, что итератор нашел модифицированную коллекцию. Просто используйте while -loop (не for -loop, потому что условие прерывания оценивается только один раз).

По-прежнему существует риск того, что форма удалена из списка после того, как вы проверили, что есть другая форма для обработки, и вы получите ArgumentOutOfRangeException. вам придется обработать эту ситуацию изящно.

Int32 index = 0; 
while (index < Application.OpenForms.Count) 
{ 
    try 
    { 
     // Try to copy the form because the index may be or may 
     // become invalid. 
     Form form = Application.OpenForms[index]; 

     // Do stuff with the form. 
    } 
    catch (ArgumentOutOfRangeException exception) 
    { 
     // Handle no longer valid index. 
    } 

    index++; 
} 

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

Если вам нужно обработать все формы в какой-то момент (например, снимок состояния приложения), это может быть единственное решение для использования -loop и повторить попытку, пока вам не удастся выполнить итерацию по всей коллекции без исключение. Конечно, существует очевидный риск того, что это никогда не произойдет, если формы открыты и закрыты с очень высокими темпами или в зависимости от вашего итерационного кода.

+0

Его вряд ли я хотел, но кажется, что нет хорошего решения. Приветствия. – Grzenio

0

Забудьте о Application.OpenForms и используйте неуправляемый WinApi.

static IEnumerable<Form> EnumOpenForms() 
{ 
    foreach (System.Diagnostics.ProcessThread thread in System.Diagnostics.Process.GetCurrentProcess().Threads) 
    { 
     List<IntPtr> hWnds = new List<IntPtr>(); 
     EnumThreadWindows(thread.Id, (hWnd, param) => { hWnds.Add(hWnd); }, IntPtr.Zero); 
     foreach(IntPtr hWnd in hWnds) 
     { 
      Form form = Control.FromHandle(hWnd) as Form; 
      if (form != null) 
      { 
       yield return form; 
      } 
     } 
    } 
} 

[System.Runtime.InteropServices.DllImport("user32.dll")] 
static extern bool EnumThreadWindows(int dwThreadId, EnumWindowProc lpEnumFunc, IntPtr lParam); 

delegate void EnumWindowProc(IntPtr hWnd, IntPtr parameter);