Muszę przeszukać hierarchię kontroli WPF w celu znalezienia formantów pasujących do podanej nazwy lub typu. W jaki sposób mogę to zrobić?
Połączyłem format szablonu używany przez Johna Myczka i powyższy algorytm Tri Q, aby utworzyć algorytm findChild, który można zastosować na dowolnym rodzicu. Pamiętaj, że rekurencyjne przeszukiwanie drzewa w dół może być długim procesem. Sprawdziłem to tylko w aplikacji WPF, skomentuj wszelkie błędy, które możesz znaleźć, a ja poprawię mój kod.
WPF Snoop to przydatne narzędzie do przeglądania drzewa wizualnego - zdecydowanie zalecam używanie go podczas testowania lub używania tego algorytmu do sprawdzania pracy.
W algorytmie Tri Q jest mały błąd. Po znalezieniu dziecka, jeśli childCount jest> 1 i iterujemy ponownie, możemy zastąpić poprawnie znalezione dziecko. Dlatego dodałem if (foundChild != null) break;
do mojego kodu a, aby poradzić sobie z tym warunkiem.
/// <summary>
/// Finds a Child of a given item in the visual tree.
/// </summary>
/// <param name="parent">A direct parent of the queried item.</param>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.</returns>
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
Nazwij to tak:
TextBox foundTextBox =
UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "myTextBoxName");
Uwaga Application.Current.MainWindow
może być dowolnym oknem nadrzędnym.
FrameworkElement
jako T, zwróci null, gdy tylko pierwsza pętla się zakończy. więc będziesz musiał dokonać modyfikacji.Możesz również znaleźć element według nazwy, używając FrameworkElement.FindName (string) .
Dany:
W pliku za kodem możesz napisać:
Oczywiście, ponieważ definiuje się go za pomocą x: Nazwa, możesz po prostu odwoływać się do wygenerowanego pola, ale być może chcesz to sprawdzić dynamicznie, a nie statycznie.
To podejście jest również dostępne w przypadku szablonów, w których nazwany element pojawia się wiele razy (raz na użycie szablonu).
źródło
Za pomocą VisualTreeHelper można znaleźć formanty. Poniżej znajduje się metoda wykorzystująca VisualTreeHelper do znalezienia kontroli nadrzędnej określonego typu. Możesz użyć VisualTreeHelper, aby znaleźć formanty również na inne sposoby.
Nazwij to tak:
źródło
Być może powtarzam wszystkim innym, ale mam ładny fragment kodu, który rozszerza klasę DependencyObject za pomocą metody FindChild (), która da ci dziecko według typu i imienia. Wystarczy dołączyć i użyć.
Mam nadzieję, że uznasz to za przydatne.
źródło
Moje rozszerzenia do kodu.
Źródło: https://code.google.com/p/gishu-util/source/browse/#git%2FWPF%2FUtilities
Objaśniający post na blogu: http://madcoderspeak.blogspot.com/2010/04/wpf-find-child-control-of-specific-type.html
źródło
Jeśli chcesz znaleźć WSZYSTKIE formanty określonego typu, ten fragment kodu może Cię również zainteresować
źródło
child
po raz drugi? Jeśli maszchildType
typT
, możesz pisać wewnątrzif
:yield return childType
... nie?Spowoduje to odrzucenie niektórych elementów - powinieneś rozszerzyć go w ten sposób, aby obsługiwać szerszą gamę elementów sterujących. Krótka dyskusja znajduje się tutaj
źródło
Try*
metoda zwrócibool
i będzie miećout
parametr, który zwraca dany typ, jak w przypadku:bool IDictionary.TryGetValue(TKey key, out TValue value)
FindParent
. Ta nazwa sugeruje, że może wrócićnull
.Try*
Prefiks jest używany na całym BCL w sposób opisuję powyżej. Zauważ też, że większość innych odpowiedzi tutaj używaFind*
konwencji nazewnictwa. To tylko drobna uwaga :)Edytowałem kod CrimsonX, ponieważ nie działał on z typami nadklasy:
źródło
DependencyObject
nie jestFrameworkElement
to, może zgłosić wyjątek. Również używanieGetChildrenCount
przy każdej iteracjifor
pętli wydaje się złym pomysłem.Chociaż ogólnie uwielbiam rekurencję, nie jest ona tak skuteczna jak iteracja podczas programowania w C #, więc może poniższe rozwiązanie jest fajniejsze niż to zaproponowane przez Johna Myczka? Przeszukuje hierarchię z danego elementu sterującego, aby znaleźć element nadrzędny określonego typu.
Nazwij to tak, aby znaleźć
Window
formant zawierającyExampleTextBox
:źródło
Oto mój kod, aby znaleźć formanty według typu, jednocześnie kontrolując, jak głęboko wchodzimy do hierarchii (maxDepth == 0 oznacza nieskończenie głęboką).
źródło
exciton80 ... Miałem problem z tym, że Twój kod nie powtarza się przez kontrolki użytkownika. Uderzał w korzeń siatki i generował błąd. Myślę, że to naprawia to dla mnie:
źródło
Mam taką funkcję sekwencji (która jest całkowicie ogólna):
Pierwsze natychmiastowe dzieci:
Znalezienie wszystkich dzieci w drzewie hiararchicznym:
Możesz to wywołać w oknie, aby uzyskać wszystkie elementy sterujące.
Po utworzeniu kolekcji możesz użyć LINQ (tj. OfType, Where).
źródło
Ponieważ pytanie jest na tyle ogólne, że może przyciągnąć ludzi szukających odpowiedzi na bardzo trywialne przypadki: jeśli chcesz po prostu dziecka, a nie potomka, możesz użyć Linq:
lub oczywiście oczywiste dla iteracji pętli nad dziećmi.
źródło
Te opcje mówią już o przechodzeniu przez Visual Tree w C #. Możliwe jest również przeglądanie drzewa wizualnego w Xaml przy użyciu rozszerzenia znaczników RelativeSource. msdn
znajdź według rodzaju
źródło
Oto rozwiązanie wykorzystujące elastyczny predykat:
Możesz na przykład nazwać to tak:
źródło
Ten kod naprawia tylko błąd odpowiedzi @CrimsonX:
Musisz tylko wywoływać metodę rekurencyjnie, jeśli typy są zgodne, ale nazwy się nie zgadzają (dzieje się tak, gdy podajesz
FrameworkElement
jakoT
). inaczej to wrócinull
i to źle.źródło
Aby znaleźć przodka danego typu na podstawie kodu, możesz użyć:
Ta implementacja wykorzystuje iterację zamiast rekurencji, która może być nieco szybsza.
Jeśli używasz C # 7, można to zrobić nieco krócej:
źródło
Spróbuj tego
Kod za
źródło