Domanda

All'interno di un evento, vorrei porre l'attenzione su una specifica casella di testo all'interno ListViewItem del modello.Il codice XAML assomiglia a questo:

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

Ho provato il seguente nel codice sottostante:

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

ma mi sembra di aver frainteso il FindName() docs, perché restituisce null.

Anche il ListView.Items non aiuta, perché (ovviamente) contiene il mio vincolato business objects e ListViewItems.

Non myList.ItemContainerGenerator.ContainerFromItem(item), che, inoltre, restituisce null.

È stato utile?

Soluzione

Per capire perché ContainerFromItem non ha funzionato per me, qui un po ' di sfondo.Il gestore di eventi in cui avevo bisogno di questa funzionalità simile a questo:

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

Dopo il Add() il ItemContainerGenerator non creare immediatamente il contenitore, perché il CollectionChanged evento può essere gestito su un non-UI-thread.Invece si inizia una chiamata asincrona e attende che il thread dell'interfaccia utente di callback e di eseguire l'effettivo controllo ListViewItem generazione.

Per essere avvisato quando questo accade, il ItemContainerGenerator espone un StatusChanged evento che viene generato dopo tutti i Contenitori sono generati.

Ora devo ascoltare questo evento e decidere se il controllo attualmente vogliono per impostare la messa a fuoco o meno.

Altri suggerimenti

Come altri hanno notato, La miamacchina TextBox non può essere trovato da chiamare FindName sulla ListView.Tuttavia, è possibile ottenere il ListViewItem che è attualmente selezionato, e utilizzare il VisualTreeHelper classe per ottenere la casella di testo da ListViewItem.Per farlo è qualcosa di simile a questo:

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;
}

Ho notato che il titolo della domanda non è direttamente correlata al contenuto della domanda, e non è accettato risposta della risposta.Sono stato in grado di "accesso ListViewItems di WPF ListView" usando questo:

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);
    }
}

Io non sono sicuro di come frenetica la ricorsione si, ma non sembrava funzionare bene nel mio caso.E no, non ho usato yield return in ricorsiva in contesto di prima.

Si può attraversare il ViewTree a trovare la voce"ListViewItem'set di record che corrisponde alla cella attivata da hit test.

Allo stesso modo, è possibile ottenere le intestazioni di colonna dal padre a confrontare e abbinare la cella della colonna.È possibile associare il nome della cella di intestazione della colonna nome come chiave per il tuo comparatore delegato/filtro.

Per esempio:HitResult è sul Testo evidenziato in verde.Si desidera ottenere l'handle per l' 'ListViewItem'.

enter image description here

/// <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));
}

Abbiamo usato una tecnica simile con WPF nuovo datagrid:

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

La tecnica dovrebbe essere abbastanza applicabile per voi, basta passare il vostro listviewitem una volta generato.

O può essere fatto semplicemente da

private void yourtextboxinWPFGrid_LostFocus(object sender, RoutedEventArgs e)
    {
       //textbox can be catched like this. 
       var textBox = ((TextBox)sender);
       EmailValidation(textBox.Text);
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top