0

[紹介]サンプルの WPF アプリケーションがあります。ボタンをクリックすると、新しいウィンドウが開きます。内部にデータがロードされるまでしばらく待つ必要があります。受け身で待つのではなく、その間に別のことをしたい。たとえば、コンテキスト メニューを開くことができます。この状況を次の画面に示します。

ここに画像の説明を入力

この待機ウィンドウは、ロードが完了した直後 (データを表示する準備ができている) に、フォーカスがグリッドに設定されたイベントを発生させます。

void DataLoaded(object sender, EventArgs e)
{             
    grid.Focus();
    grid.SelectedIndex = 0;
}

[現在の問題]残念ながら、まったく同じ瞬間に、最近開いたコンテキスト メニューが消えてしまいました。フォーカスが強制的に盗まれました。迷惑な最終的な効果を以下に示します。

ここに画像の説明を入力

【望む効果】ハッピーエンドとは?ユーザーが他の要素 (コンテキスト メニューなど) に変更した場合、自動フォーカスは行われません。つまり、フォーカスを奪わないでください。

ここに画像の説明を入力

コードの変更は次のとおりです。

void DataLoaded(object sender, EventArgs e)
{
    if (Magic.FocusNotChanged)
    {                
        grid.Focus();
        grid.SelectedIndex = 0;
    }
}

しかし、魔法とは何ですか?自動フォーカス変更を許可または拒否するグローバル パブリッシュ サブスクライブ メカニズムはありますか? フォーカスの変更をスパイしているハンドラーはありますか?

ところで: 上記の特定のアプリケーションは、より広いコンテキストから人為的に抽出されたものです。ここで実装されたレイアウトにはあまり注意を払わないでください。この特定のボタンやコンテキスト メニューに関係なく、いくつかの一般的なメカニズムを考案する必要があります。手がかりはありますか?よろしく。

4

1 に答える 1

0

解決策は平凡です-非侵襲的な方法で焦点を合わせるには、その時にウィンドウがアクティブかどうかを確認します:

void DataLoaded(object sender, EventArgs e)
{
    if (this.IsActive)
    {                
        grid.Focus();
        grid.SelectedIndex = 0;
    }
}

その他の機能強化:

より一般的なソリューションが必要だとします。ウィンドウ自体からではなく、ウィンドウによってホストされている特定のコントロール内からフォーカスを設定したい場合はどうすればよいIsActiveでしょうか (プロパティの欠如)。親ウィンドウを見つけて、まだアクティブかどうかを確認する必要があります。さらに、このコントロールに多数の子コントロールが含まれており、特定の子にフォーカスを設定したいとします。これを見てください:

void DataLoaded(object sender, EventArgs e)
{
    var window = this.GetParent<Window>();
    if (window.IsActive)
    {         
        var grid = this.GetChild<DataGrid>();
        grid.Focus();
    }
}

2 つのヘルパー メソッドの使用法を確認できます。それらの実装を以下に示します。

public static T GetParent<T>(this DependencyObject child) where T : DependencyObject
{
    if (child == null) return null;

    // get parent item
    var parentObject = VisualTreeHelper.GetParent(child);
    // we’ve reached the end of the tree
    if (parentObject == null) return null;
    // check if the parent matches the type we’re looking for
    var parent = parentObject as T;
    // return parent if match or use recursion to proceed with next level
    return parent ?? GetParent<T>(parentObject);            
}

public static T GetChild<T>(this DependencyObject parent) where T : DependencyObject
{
    if (parent == null) return null;
    T result = null;

    var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
    for (var i = 0; i < childrenCount; i++)
    {
        var childObject = VisualTreeHelper.GetChild(parent, i);
        var child = childObject as T;
        if (child == null)
            result = childObject.GetChild<T>();
        else
        {
            result = (T) childObject;
            break;
        }
    }   
    return result;
}
于 2013-11-08T10:10:37.340 に答える