Как проверить загрузку файла с помощью Watin/IE9?

Я пытаюсь загрузить файл с Watin 2.1.0 против IE9. Я использовал предложенный код из принятого ответа на вопрос Загрузка файла с Watin в IE9, например:

var downloadHandler = new FileDownloadHandler(fname);
WebBrowser.Current.AddDialogHandler(downloadHandler);
link.ClickNoWait();
downloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
downloadHandler.WaitUntilDownloadCompleted(200);

Однако вызов downloadHandler.WaitUntilFileDownloadDialogIsHandled(15) истекает. Что мне делать?

Ответ 1

IE9 больше не использует диалоговое окно для сохранения файлов. Вместо этого он использует панель уведомлений, чтобы предотвратить удаление фокуса с веб-сайта. См. http://msdn.microsoft.com/en-us/ie/ff959805.aspx в разделе "Менеджер загрузки" для справки.

К сожалению, это означает, что текущий FileDownloadHandler в WatiN не будет работать. Он создает экземпляр класса "DialogWatcher" для каждого экземпляра браузера, который является базовым насосом сообщений для любого дочернего окна. Когда дочерние окна встречаются, DialogWatcher проверяет, является ли окно конкретным диалогом (которого нет в панели уведомлений). Если это диалог, он выполняет итерацию над зарегистрированными экземплярами IDialogHandler, вызывающими "CanHandleDialog". Даже если панель уведомлений была диалогом, она отличается от Window Style (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx), так как WatiN обнаруживает тип диалога.

Из того, что я вижу, пока нет поддержки для обнаружения панели уведомлений IE 9 и ее подсказок в WatiN. Пока эта поддержка не будет добавлена, вы не сможете автоматизировать загрузку файлов в IE9.

Ответ 2

Диалоговое окно загрузки файлов не работает в IE9 (Windows7) NetFramework 4.0.

Следующий фрагмент кода может помочь вам решить проблему:

Сначала вы должны добавить в свой тестовый проект ссылки UIAutomationClient и UIAutomationTyp.

After In Ie9 Tools → Просмотр загрузок → Параметры определяют путь к вашей папке сохранения.

Следующий метод расширяет класс браузера

public static void DownloadIEFile(this Browser browser)
{
    // see information here (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx)
    Window windowMain = new Window(WatiN.Core.Native.Windows.NativeMethods.GetWindow(browser.hWnd, 5));
   System.Windows.Automation.TreeWalker trw = new  System.Windows.Automation.TreeWalker(System.Windows.Automation.Condition.TrueCondition);
   System.Windows.Automation.AutomationElement mainWindow = trw.GetParent(System.Windows.Automation.AutomationElement.FromHandle(browser.hWnd));

    Window windowDialog = new Window(WatiN.Core.Native.Windows.NativeMethods.GetWindow(windowMain.Hwnd, 5));
    // if doesn't work try to increase sleep interval or write your own waitUntill method
    Thread.Sleep(1000);
    windowDialog.SetActivate();
    System.Windows.Automation.AutomationElementCollection amc = System.Windows.Automation.AutomationElement.FromHandle(windowDialog.Hwnd).FindAll(System.Windows.Automation.TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);

    foreach (System.Windows.Automation.AutomationElement element in amc)
    {
        // You can use "Save ", "Open", ''Cancel', or "Close" to find necessary button Or write your own enum
        if (element.Current.Name.Equals("Save"))
        {
            // if doesn't work try to increase sleep interval or write your own waitUntil method
            // WaitUntilButtonExsist(element,100);
            Thread.Sleep(1000);
            System.Windows.Automation.AutomationPattern[] pats = element.GetSupportedPatterns();
            // replace this foreach if you need 'Save as' with code bellow
            foreach (System.Windows.Automation.AutomationPattern pat in pats)
            {
                // '10000' button click event id 
                if (pat.Id == 10000)
                {
                    System.Windows.Automation.InvokePattern click = (System.Windows.Automation.InvokePattern)element.GetCurrentPattern(pat);
                    click.Invoke();
                }
            }
        }
    }
}

если вы хотите нажать "Сохранить как", замените код foreach на этот

System.Windows.Automation.AutomationElementCollection bmc =  element.FindAll(System.Windows.Automation.TreeScope.Children,   System.Windows.Automation.Automation.ControlViewCondition);
System.Windows.Automation.InvokePattern click1 =  (System.Windows.Automation.InvokePattern)bmc[0].GetCurrentPattern(System.Windows.Automation.AutomationPattern.LookupById(10000));
click1.Invoke();
Thread.Sleep(10000);

System.Windows.Automation.AutomationElementCollection main =  mainWindow.FindAll(System.Windows.Automation.TreeScope.Children
,System.Windows.Automation.Condition.TrueCondition);
foreach (System.Windows.Automation.AutomationElement el in main)
{
    if (el.Current.LocalizedControlType == "menu")
    {
        // first array element 'Save', second array element 'Save as', third second array element    'Save and open'
        System.Windows.Automation.InvokePattern clickMenu = (System.Windows.Automation.InvokePattern)
                    el.FindAll(System.Windows.Automation.TreeScope.Children,        System.Windows.Automation.Condition.TrueCondition)  [1].GetCurrentPattern(System.Windows.Automation.AutomationPattern.LookupById(10000));
                       clickMenu.Invoke();
        //add ControlSaveDialog(mainWindow, filename) here if needed
        break;

    }
}

Изменить: Кроме того, если вам нужно автоматизировать сохранение как диалоговое окно с указанием пути и нажатием кнопки "Сохранить", вы можете сделать это, добавив этот код непосредственно перед break;

private static void ControlSaveDialog(System.Windows.Automation.AutomationElement mainWindow, string path)
{
    //obtain the save as dialog
    var saveAsDialog = mainWindow
                        .FindFirst(TreeScope.Descendants,
                                   new PropertyCondition(AutomationElement.NameProperty, "Save As"));
    //get the file name box
    var saveAsText = saveAsDialog
            .FindFirst(TreeScope.Descendants,
                       new AndCondition(
                           new PropertyCondition(AutomationElement.NameProperty, "File name:"),
                           new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)))
            .GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
    //fill the filename box 
    saveAsText.SetValue(path);

    Thread.Sleep(1000);
    //find the save button
    var saveButton =
            saveAsDialog.FindFirst(TreeScope.Descendants,
            new AndCondition(
                new PropertyCondition(AutomationElement.NameProperty, "Save"),
                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)));
    //invoke the button
    var pattern = saveButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
    pattern.Invoke();
}