Как получить доступ к ячейкам GridView с помощью Winappdriver?

Я пытаюсь получить значение ячейки из GridView в проекте WPF с помощью winappdriver.

У меня проблема с этой строкой:

 string name = row.FindElementByName("Name1").Text;

Не удалось найти элемент на странице с заданными параметрами поиска.

Не могли бы вы проверить мой следующий код:

 <Grid>
        <ListView Margin="10" Name="lvUsers" AutomationProperties.AutomationId="lvUsers">
                <ListView.View>
                <GridView x:Name="ListViewItem"  AutomationProperties.AutomationId="ListViewItem">
                        <GridViewColumn x:Name="Name1" AutomationProperties.Name="Name1" AutomationProperties.AutomationId="Name1" Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
                        <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
                        <GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
                    </GridView>
                </ListView.View>
            </ListView>
  </Grid>

 var listBox = session.FindElementByAccessibilityId("lvUsers");
            var comboBoxItems = listBox.FindElementsByClassName("ListViewItem");
             foreach (var row  in  comboBoxItems)
             {
                string name = row.FindElementByName("Name1").Text;
                if (name == "John Doe")
                {                     
                   findName = true;
                   break;
                }
         }
        Assert.AreEqual(findName, true);

person Mike Darwish    schedule 27.06.2020    source источник
comment
Наверное, не то, что вы хотите услышать, но ... Обычно автоматизируют тесты на моделях представления wpf, а не на представлениях. Итерация по сетке данных или списку для поиска содержимого ячейки всегда будет болезненной. Столбец gridview - вещь абстрактная. Вы не найдете его в визуальном дереве. Я рекомендую вам загрузить snoop (есть другая версия для ядра .net) и использовать ее, чтобы изучить, что вы на самом деле получаете в своем пользовательском интерфейсе при запуске.   -  person Andy    schedule 27.06.2020
comment
WinAppDrive использует автоматизацию пользовательского интерфейса. Используйте inspect.exe из Windows SDK, чтобы проверить, что UI Automation видит из вашего запущенного приложения. github.com/microsoft/WinAppDriver/blob/ master / Docs / Только классы, производные от UIElement, могут поддерживать автоматизацию пользовательского интерфейса. GridViewColumn не является UIElement   -  person Simon Mourier    schedule 30.06.2020


Ответы (2)


Очевидно, вы выбрали неправильный инструмент для выполнения своей задачи. Автоматизация предназначена для работы с элементами пользовательского интерфейса, но вам нужны данные для выполнения задачи. Посмотрите, как выглядит визуальное дерево вашей DataGrid:

введите описание изображения здесь

DataGrid унаследован от ItemsControl. А в его визуализации - только ряды. Нет столбцов. Извлечь данные из конкретной ячейки можно, но это очень сложно и не имеет смысла.

Вам нужно создать нормальный источник данных. Для начала возьмем какую-то реализацию INotifyPropertyChanged. Например, это:

/// <summary>Base class implementing INotifyPropertyChanged.</summary>
public abstract class BaseINPC : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>Called AFTER the property value changes.</summary>
    /// <param name="propertyName">The name of the property.
    /// In the property setter, the parameter is not specified. </param>
    public void RaisePropertyChanged([CallerMemberName] string propertyName = "")
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    /// <summary> A virtual method that defines changes in the value field of a property value. </summary>
    /// <typeparam name = "T"> Type of property value. </typeparam>
    /// <param name = "oldValue"> Reference to the field with the old value. </param>
    /// <param name = "newValue"> New value. </param>
    /// <param name = "propertyName"> The name of the property. If <see cref = "string.IsNullOrWhiteSpace (string)" />,
    /// then ArgumentNullException. </param> 
    /// <remarks> If the base method is not called in the derived class,
    /// then the value will not change.</remarks>
    protected virtual void Set<T>(ref T oldValue, T newValue, [CallerMemberName] string propertyName = "")
    {
        if (string.IsNullOrWhiteSpace(propertyName))
            throw new ArgumentNullException(nameof(propertyName));

        if ((oldValue == null && newValue != null) || (oldValue != null && !oldValue.Equals(newValue)))
            OnValueChange(ref oldValue, newValue, propertyName);
    }

    /// <summary> A virtual method that changes the value of a property. </summary>
    /// <typeparam name = "T"> Type of property value. </typeparam>
    /// <param name = "oldValue"> Reference to the property value field. </param>
    /// <param name = "newValue"> New value. </param>
    /// <param name = "propertyName"> The name of the property. </param>
    /// <remarks> If the base method is not called in the derived class,
    /// then the value will not change.</remarks>
    protected virtual void OnValueChange<T>(ref T oldValue, T newValue, string propertyName)
    {
        oldValue = newValue;
        RaisePropertyChanged(propertyName);
    }

}

На его основе вы можете создать тип для коллекции:

public class PersonVM : BaseINPC
{
    private string _name;
    private uint _age;
    private string _mail;

    public string Name { get => _name; set => Set(ref _name, value); }
    public uint Age { get => _age; set => Set(ref _age, value); }
    public string Mail { get => _mail; set => Set(ref _mail, value); }
}

И ViewModel с коллекцией:

public class ViewModel
{
    public ObservableCollection<PersonVM> People { get; } 
        = new ObservableCollection<PersonVM>()
        {
            new PersonVM(){Name="Peter", Age=20, Mail="[email protected]"},
            new PersonVM(){Name="Alex", Age=30, Mail="[email protected]"},
            new PersonVM(){Name="Nina", Age=25, Mail="[email protected]"},
        };
}

Подключите его к DataContext Windows:

<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>
<Grid>
    <ListView Margin="10" ItemsSource="{Binding People}">
        <ListView.View>
            <GridView x:Name="ListViewItem" >
                <GridViewColumn x:Name="Name1" Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
                <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
                <GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
            </GridView>
        </ListView.View>
    </ListView>
</Grid>

Теперь ваша задача сводится к поиску нужного предмета в коллекции People.

person EldHasp    schedule 02.07.2020

Если вам известно точное расположение ячейки (например, строка x, столбец y) в сетке, используйте следующий пользовательский код.
У меня это сработало, мне нужно было получить номер в 3-й строке, 2-м столбце. В сетке 6 столбцов.

var gridItemsCollection = grid.FindElementsByXPath("//ListItem/Text");
List<int> allIds = HelperClass.GetColumnValuesFromGrid(gridItemsCollection, 6,2).ConvertAll(int.Parse);
var myId = allIds[2];//3rd row. 3-1

Ниже приводится определение функции. (Хотя не идеальный код)

public static List<string> GetColumnValuesFromGrid(IReadOnlyCollection<AppiumWebElement> gridItemsCollection, int gridColumns, int selectColumn)
    {
        List<string> list = new List<string>();
    List<string> selectList = new List<string>();

int index = selectColumn - 1;
if (index < 0 || gridItemsCollection.Count == 0)
{
return null;
}

foreach (var element in gridItemsCollection)
{
    list.Add(element.Text);
}            

while (index < list.Count)
{
    selectList.Add(list[index]);
    index += gridColumns;
}

return selectList;
}

Мне тоже нужно было набрать максимальное количество. Итак, я сделал следующее.

allIds.Sort();
allIds.Reverse();
var maxId = allIds[0];
person Rahul Joshi    schedule 22.09.2020