16

イベント内で、ListViewItem のテンプレート内の特定の TextBox にフォーカスを置きたいと思います。XAML は次のようになります。

<ListView x:Name="myList" ItemsSource="{Binding SomeList}">
    <ListView.View>
        <GridView>
            <GridViewColumn>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <!-- Focus this! -->
                        <TextBox x:Name="myBox"/>

コードビハインドで次のことを試しました。

(myList.FindName("myBox") as TextBox).Focus();

FindName()が返されるため、ドキュメントを誤解しているようですnull

また、ListView.Items(もちろん) バインドされたビジネス オブジェクトが含まれており、ListViewItems が含まれていないため、これも役に立ちません。

どちらmyList.ItemContainerGenerator.ContainerFromItem(item)も null を返します。

4

6 に答える 6

21

なぜContainerFromItemうまくいかなかったのかを理解するために、ここでいくつかの背景を説明します。この機能が必要なイベント ハンドラーは次のようになります。

var item = new SomeListItem();
SomeList.Add(item);
ListViewItem = SomeList.ItemContainerGenerator.ContainerFromItem(item); // returns null

イベントは非 UI スレッドで処理される可能性があるため、コンテナはすぐには作成されませAdd()ん。代わりに、非同期呼び出しを開始し、UI スレッドがコールバックして実際の ListViewItem コントロールの生成を実行するのを待ちます。ItemContainerGeneratorCollectionChanged

これが発生したときに通知を受けるために、 は、すべてのコンテナが生成された後に発生ItemContainerGeneratorするイベントを公開します。StatusChanged

ここで、このイベントをリッスンして、コントロールが現在フォーカスを設定する必要があるかどうかを判断する必要があります。

于 2009-02-02T09:02:33.323 に答える
14

他の人が指摘したように、ListView で FindName を呼び出しても myBox TextBox を見つけることができません。ただし、現在選択されている ListViewItem を取得し、VisualTreeHelper クラスを使用して ListViewItem から TextBox を取得できます。これを行うには、次のようになります。

private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (myList.SelectedItem != null)
    {
        object o = myList.SelectedItem;
        ListViewItem lvi = (ListViewItem)myList.ItemContainerGenerator.ContainerFromItem(o);
        TextBox tb = FindByName("myBox", lvi) as TextBox;

        if (tb != null)
            tb.Dispatcher.BeginInvoke(new Func<bool>(tb.Focus));
    }
}

private FrameworkElement FindByName(string name, FrameworkElement root)
{
    Stack<FrameworkElement> tree = new Stack<FrameworkElement>();
    tree.Push(root);

    while (tree.Count > 0)
    {
        FrameworkElement current = tree.Pop();
        if (current.Name == name)
            return current;

        int count = VisualTreeHelper.GetChildrenCount(current);
        for (int i = 0; i < count; ++i)
        {
            DependencyObject child = VisualTreeHelper.GetChild(current, i);
            if (child is FrameworkElement)
                tree.Push((FrameworkElement)child);
        }
    }

    return null;
}
于 2008-09-18T13:57:59.960 に答える
4

質問のタイトルは質問の内容に直接関係しておらず、受け入れられた回答もそれに答えていないことに気づきました。これを使用して、「WPFListViewのListViewItemsにアクセス」することができました。

public static IEnumerable<ListViewItem> GetListViewItemsFromList(ListView lv)
{
    return FindChildrenOfType<ListViewItem>(lv);
}

public static IEnumerable<T> FindChildrenOfType<T>(this DependencyObject ob)
    where T : class
{
    foreach (var child in GetChildren(ob))
    {
        T castedChild = child as T;
        if (castedChild != null)
        {
            yield return castedChild;
        }
        else
        {
            foreach (var internalChild in FindChildrenOfType<T>(child))
            {
                yield return internalChild;
            }
        }
    }
}

public static IEnumerable<DependencyObject> GetChildren(this DependencyObject ob)
{
    int childCount = VisualTreeHelper.GetChildrenCount(ob);

    for (int i = 0; i < childCount; i++)
    {
        yield return VisualTreeHelper.GetChild(ob, i);
    }
}

再帰がどれほど多忙になるかはわかりませんが、私の場合は問題なく機能しているようです。いいえ、これまでyield return再帰的なコンテキストで使用したことはありません。

于 2012-10-25T17:09:34.157 に答える
0

ViewTree を上に移動して、ヒット テストからトリガーされたセルに対応する項目 ' ListViewItem ' レコード セットを見つけることができます。

同様に、親ビューから列ヘッダーを取得して、セルの列と比較して一致させることができます。コンパレータデリゲート/フィルターのキーとして、セル名を列ヘッダー名にバインドすることができます。

例: HitResult は、緑色で示されている TextBlock にあります。「 ListViewItem 」へのハンドルを取得したいと考えています。

ここに画像の説明を入力

/// <summary>
///   ListView1_MouseMove
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListView1_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) {
  if (ListView1.Items.Count <= 0)
    return;

  // Retrieve the coordinate of the mouse position.
  var pt = e.GetPosition((UIElement) sender);

  // Callback to return the result of the hit test.
  HitTestResultCallback myHitTestResult = result => {
    var obj = result.VisualHit;

    // Add additional DependancyObject types to ignore triggered by the cell's parent object container contexts here.
    //-----------
    if (obj is Border)
      return HitTestResultBehavior.Stop;
    //-----------

    var parent = VisualTreeHelper.GetParent(obj) as GridViewRowPresenter;
    if (parent == null)
      return HitTestResultBehavior.Stop;

    var headers = parent.Columns.ToDictionary(column => column.Header.ToString());

    // Traverse up the VisualTree and find the record set.
    DependencyObject d = parent;
    do {
      d = VisualTreeHelper.GetParent(d);
    } while (d != null && !(d is ListViewItem));

    // Reached the end of element set as root's scope.
    if (d == null)
      return HitTestResultBehavior.Stop;

    var item = d as ListViewItem;
    var index = ListView1.ItemContainerGenerator.IndexFromContainer(item);
    Debug.WriteLine(index);

    lblCursorPosition.Text = $"Over {item.Name} at ({index})";

    // Set the behavior to return visuals at all z-order levels.
    return HitTestResultBehavior.Continue;
  };

  // Set up a callback to receive the hit test result enumeration.
  VisualTreeHelper.HitTest((Visual)sender, null, myHitTestResult, new PointHitTestParameters(pt));
}
于 2017-03-02T22:31:34.947 に答える
-1

WPFの新しいデータグリッドでも同様の手法を使用します。

Private Sub SelectAllText(ByVal cell As DataGridCell)
    If cell IsNot Nothing Then
        Dim txtBox As TextBox= GetVisualChild(Of TextBox)(cell)
        If txtBox IsNot Nothing Then
            txtBox.Focus()
            txtBox.SelectAll()
        End If
    End If
End Sub

Public Shared Function GetVisualChild(Of T As {Visual, New})(ByVal parent As Visual) As T
    Dim child As T = Nothing
    Dim numVisuals As Integer = VisualTreeHelper.GetChildrenCount(parent)
    For i As Integer = 0 To numVisuals - 1
        Dim v As Visual = TryCast(VisualTreeHelper.GetChild(parent, i), Visual)
        If v IsNot Nothing Then
            child = TryCast(v, T)
            If child Is Nothing Then
                child = GetVisualChild(Of T)(v)
            Else
                Exit For
            End If
        End If
    Next
    Return child
End Function

この手法はあなたにかなり適用できるはずです。生成されたらlistviewitemを渡すだけです。

于 2008-09-18T14:15:27.653 に答える
-1

またはそれは簡単に行うことができます

private void yourtextboxinWPFGrid_LostFocus(object sender, RoutedEventArgs e)
    {
       //textbox can be catched like this. 
       var textBox = ((TextBox)sender);
       EmailValidation(textBox.Text);
    }
于 2010-09-13T11:09:00.937 に答える