読者です 読者をやめる 読者になる 読者になる

ささいなことですが。

Windowsアプリテスト自動化ライブラリFriendly開発者の日記です。

Friendly.WPFStandardControls.1.4.0を公開しました。

NuGet Gallery | Friendly.WPFStandardControls 1.6.0
今回は機能追加です。

ボタン検索

前回のバージョンアップでは、DependencyObjectに対して、バインディングとタイプで検索する機能を追加しました。
Friendly.WPFStandardControls.1.3.0をリリースしました。 - ささいなことですが。

これで大体取れるのですが、ボタンはApplicationCommandsを設定することが多く、また画面に複数個あることが普通であったために上記の手法で取れないことがありました。
それでコマンドから検索する機能も共通で定義しました。

例として次の画面でボタンを特定してみます。

<Window x:Class="Target.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="115" Width="238">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Button Content="Close" Command="ApplicationCommands.Close"/>
        <Button Content="A" CommandParameter="A" Grid.Column="1"/>
    </Grid>
</Window>

f:id:ishikawa-tatsuya:20150720225054p:plain

特定する部分のコードです。

var app = new WindowsAppFriend(Process.Start("Target.exe"));
WindowControl main = WindowControl.FromZTop(app);

//ApplicationCommands.Closeの割り当たっているボタンを特定
var buttonClose = main.LogicalTree().ByType<Button>().ByCommand(ApplicationCommands.Close).Single();

//CommandParameterから特定
var buttonA = main.LogicalTree().ByType<Button>().ByCommandParameter("A").Single();

前回追加したByBining、ByTypeはDependencyObjectに対応するAppVar、IAppVarOwnerに対して使えました。今回のはButtonBaseを継承しオブジェクトに対して使えます。ポイントはByTypeです。

IWPFDependencyObjectCollection<Button> elments = main.LogicalTree().ByType<Button>();

ByCommand、ByCommandParameterはIWPFDependencyObjectCollection<Button>に対する拡張メソッドになっています。

前回同様、対象プロセスの中でも使えます。複雑なことをする場合はDLLインジェクションでコードを送り込んで検索してください。

//インジェクションするコード
static Button Search(Window window)
{
    var buttons = window.LogicalTree().ByType<Button>();
    var button = buttons.ByCommand(ApplicationCommands.Close).Single();

    //対象が.net3.0アプリの場合は拡張メソッドが使えないのでこちらを利用してください。
    button = ButtonSearcherInTarget.ByCommand(buttons, ApplicationCommands.Close).Single();
    button button;
}

TreeViewItemのヘッダー

TreeViewItemに対応するオブジェクトを取得する手段は今までも提供していました。しかし、TreeViewItemはそれ自体が階層型になっています。そこからさらにコントロールを検索する場合はヘッダー部分のみ検索する必要があります。今回はそれを提供しました。

例えば、こんなツリーがあって、
f:id:ishikawa-tatsuya:20150720230842p:plain
アイテムのボタンをとるならこんな感じ。

WPFTreeView tree = new WPFTreeView(window.LogicalTree().ByBinding("TreeData"));
var item = tree.GetItem(1);
//ヘッダー部分を取得
var header = item.HeaderContent;
//そのビジュアルツリーから目的のコントロールを取得
var button = new WPFButtonBase(header.VisualTree().ByType<Button>().Single());
button.EmulateClick();

ご要望あれば連絡ください。

その他、「これも検索方法を提供して欲しいんだけど」みたいなのがあれば連絡いただければ対応できるかもしれません。もし共通化するのは難しかったとしても、Friendlyの基本機能を使えば、ほとんどは検索可能なのでアドバイスくらいはできます。(x:Name使えばいいじゃんとかw)
よろしくお願いします!