Tôi đang tìm cách để tìm tất cả các điều khiển trên Window theo loại của chúng,
ví dụ: tìm tất cả TextBoxes
, tìm tất cả các điều khiển thực hiện giao diện cụ thể, v.v.
Tôi đang tìm cách để tìm tất cả các điều khiển trên Window theo loại của chúng,
ví dụ: tìm tất cả TextBoxes
, tìm tất cả các điều khiển thực hiện giao diện cụ thể, v.v.
Câu trả lời:
cái này cần phải dùng mẹo
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
sau đó bạn liệt kê các điều khiển như vậy
foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
// do something with tb here
}
this
trước DependencyObject
=>this DependencyObject depObj
Đây là cách dễ dàng nhất:
IEnumerable<myType> collection = control.Children.OfType<myType>();
trong đó điều khiển là phần tử gốc của cửa sổ.
<Grid Name="Anata_wa_yoru_o_shihai_suru_ai">here buttons</Grid>
và sau đó tôi có thể sử dụngAnata_wa_yoru_o_shihai_suru_ai.Children.OfType<myType>();
Tôi đã điều chỉnh câu trả lời của @Bryce Kahle để làm theo gợi ý và cách sử dụng của @Mathias Lykkegaard Lorenzen LogicalTreeHelper
.
Có vẻ làm việc ổn. ;)
public static IEnumerable<T> FindLogicalChildren<T> ( DependencyObject depObj ) where T : DependencyObject
{
if( depObj != null )
{
foreach( object rawChild in LogicalTreeHelper.GetChildren( depObj ) )
{
if( rawChild is DependencyObject )
{
DependencyObject child = (DependencyObject)rawChild;
if( child is T )
{
yield return (T)child;
}
foreach( T childOfChild in FindLogicalChildren<T>( child ) )
{
yield return childOfChild;
}
}
}
}
}
(Nó vẫn sẽ không kiểm tra các điều khiển tab hoặc Lưới trong GroupBox như được đề cập bởi @Benjamin Berry & @David R tương ứng.)
Sử dụng các lớp của trình trợ giúp VisualTreeHelper
hoặc LogicalTreeHelper
tùy thuộc vào loại cây bạn quan tâm. Cả hai đều cung cấp các phương thức để lấy phần tử con của một phần tử (mặc dù cú pháp khác nhau một chút). Tôi thường sử dụng các lớp này để tìm sự xuất hiện đầu tiên của một loại cụ thể, nhưng bạn có thể dễ dàng sửa đổi nó để tìm tất cả các đối tượng của loại đó:
public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
if (obj.GetType() == type)
{
return obj;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject childReturn = FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type);
if (childReturn != null)
{
return childReturn;
}
}
}
return null;
}
Tôi thấy rằng dòng ,, VisualTreeHelper.GetChildrenCount(depObj);
được sử dụng trong một số ví dụ ở trên không trả về số khác không cho GroupBox
es, đặc biệt, trong đó GroupBox
chứa a Grid
và Grid
chứa các phần tử con. Tôi tin rằng điều này có thể là do GroupBox
không được phép chứa nhiều hơn một đứa trẻ và điều này được lưu trữ trong Content
tài sản của nó . Không có GroupBox.Children
loại tài sản. Tôi chắc chắn rằng tôi đã không làm điều này rất hiệu quả, nhưng tôi đã sửa đổi ví dụ "FindVisualChildren" đầu tiên trong chuỗi này như sau:
public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
int depObjCount = VisualTreeHelper.GetChildrenCount(depObj);
for (int i = 0; i <depObjCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
if (child is GroupBox)
{
GroupBox gb = child as GroupBox;
Object gpchild = gb.Content;
if (gpchild is T)
{
yield return (T)child;
child = gpchild as T;
}
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
Để có danh sách tất cả trẻ em thuộc một loại cụ thể, bạn có thể sử dụng:
private static IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
if (obj.GetType() == type)
{
yield return obj;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
{
if (child != null)
{
yield return child;
}
}
}
}
yield break;
}
Thay đổi nhỏ đối với đệ quy để bạn có thể tìm ví dụ điều khiển tab con của điều khiển tab.
public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child.GetType() == type)
{
return child;
}
DependencyObject childReturn = FindInVisualTreeDown(child, type);
if (childReturn != null)
{
return childReturn;
}
}
}
return null;
}
Đây là một phiên bản nhỏ gọn khác, với cú pháp chung:
public static IEnumerable<T> FindLogicalChildren<T>(DependencyObject obj) where T : DependencyObject
{
if (obj != null) {
if (obj is T)
yield return obj as T;
foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>())
foreach (T c in FindLogicalChildren<T>(child))
yield return c;
}
}
Và đây là cách nó hoạt động trở lên
private T FindParent<T>(DependencyObject item, Type StopAt) where T : class
{
if (item is T)
{
return item as T;
}
else
{
DependencyObject _parent = VisualTreeHelper.GetParent(item);
if (_parent == null)
{
return default(T);
}
else
{
Type _type = _parent.GetType();
if (StopAt != null)
{
if ((_type.IsSubclassOf(StopAt) == true) || (_type == StopAt))
{
return null;
}
}
if ((_type.IsSubclassOf(typeof(T)) == true) || (_type == typeof(T)))
{
return _parent as T;
}
else
{
return FindParent<T>(_parent, StopAt);
}
}
}
}
Xin lưu ý rằng việc sử dụng VisualTreeHelper chỉ hoạt động trên các điều khiển xuất phát từ Visual hoặc Visual3D. Nếu bạn cũng cần kiểm tra các yếu tố khác (ví dụ TextBlock, FlowDocument, v.v.), sử dụng VisualTreeHelper sẽ đưa ra một ngoại lệ.
Đây là một thay thế quay trở lại cây logic nếu cần thiết:
http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways
Tôi muốn thêm một bình luận nhưng tôi có ít hơn 50 điểm nên tôi chỉ có thể "Trả lời". Xin lưu ý rằng nếu bạn sử dụng phương thức "VisualTreeHelper" để truy xuất các đối tượng "TextBlock" của XAML thì nó cũng sẽ lấy các đối tượng "Nút" XAML. Nếu bạn khởi tạo lại đối tượng "TextBlock" bằng cách ghi vào tham số Textblock.Text thì bạn sẽ không còn có thể thay đổi văn bản Nút bằng tham số Button.Content. Nút sẽ hiển thị vĩnh viễn văn bản được ghi từ nó trong hành động ghi Textblock.Text (từ khi được truy xuất -
foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
// do something with tb here
tb.Text = ""; //this will overwrite Button.Content and render the
//Button.Content{set} permanently disabled.
}
Để khắc phục điều này, bạn có thể thử sử dụng "TextBox" XAML và thêm các phương thức (hoặc Sự kiện) để bắt chước Nút XAMAL. XAML "TextBox" không được thu thập bởi một tìm kiếm cho "TextBlock".
Phiên bản của tôi cho C ++ / CLI
template < class T, class U >
bool Isinst(U u)
{
return dynamic_cast< T >(u) != nullptr;
}
template <typename T>
T FindVisualChildByType(Windows::UI::Xaml::DependencyObject^ element, Platform::String^ name)
{
if (Isinst<T>(element) && dynamic_cast<Windows::UI::Xaml::FrameworkElement^>(element)->Name == name)
{
return dynamic_cast<T>(element);
}
int childcount = Windows::UI::Xaml::Media::VisualTreeHelper::GetChildrenCount(element);
for (int i = 0; i < childcount; ++i)
{
auto childElement = FindVisualChildByType<T>(Windows::UI::Xaml::Media::VisualTreeHelper::GetChild(element, i), name);
if (childElement != nullptr)
{
return childElement;
}
}
return nullptr;
};
Vì một số lý do, không có câu trả lời nào được đăng ở đây giúp tôi có được tất cả các điều khiển thuộc loại đã cho có trong một điều khiển nhất định trong MainWindow của tôi. Tôi cần tìm tất cả các mục trong một menu để lặp lại chúng. Họ không phải là hậu duệ trực tiếp của thực đơn, vì vậy tôi chỉ thu thập được những lilne đầu tiên trong số họ bằng cách sử dụng bất kỳ mã nào ở trên. Phương pháp mở rộng này là giải pháp của tôi cho vấn đề cho bất kỳ ai sẽ tiếp tục đọc tất cả các cách ở đây.
public static void FindVisualChildren<T>(this ICollection<T> children, DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
var brethren = LogicalTreeHelper.GetChildren(depObj);
var brethrenOfType = LogicalTreeHelper.GetChildren(depObj).OfType<T>();
foreach (var childOfType in brethrenOfType)
{
children.Add(childOfType);
}
foreach (var rawChild in brethren)
{
if (rawChild is DependencyObject)
{
var child = rawChild as DependencyObject;
FindVisualChildren<T>(children, child);
}
}
}
}
Hy vọng nó giúp.
Các câu trả lời được chấp nhận trở lại các yếu tố phát hiện nhiều hay ít không có thứ tự , bằng cách làm theo các chi nhánh đứa con đầu lòng như sâu càng tốt, trong khi năng suất các yếu tố phát hiện trên đường đi, trước khi thụt lùi và lặp lại các bước cho cành cây chưa phân tích cú pháp.
Nếu bạn cần các phần tử con theo thứ tự giảm dần , trong đó các con trực tiếp sẽ được sinh ra trước, sau đó con của chúng, v.v., thuật toán sau sẽ hoạt động:
public static IEnumerable<T> GetVisualDescendants<T>(DependencyObject parent, bool applyTemplates = false)
where T : DependencyObject
{
if (parent == null || !(child is Visual || child is Visual3D))
yield break;
var descendants = new Queue<DependencyObject>();
descendants.Enqueue(parent);
while (descendants.Count > 0)
{
var currentDescendant = descendants.Dequeue();
if (applyTemplates)
(currentDescendant as FrameworkElement)?.ApplyTemplate();
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(currentDescendant); i++)
{
var child = VisualTreeHelper.GetChild(currentDescendant, i);
if (child is Visual || child is Visual3D)
descendants.Enqueue(child);
if (child is T foundObject)
yield return foundObject;
}
}
}
Các yếu tố kết quả sẽ được sắp xếp từ gần nhất đến xa nhất. Điều này sẽ hữu ích, ví dụ nếu bạn đang tìm kiếm phần tử con gần nhất của một số loại và điều kiện:
var foundElement = GetDescendants<StackPanel>(someElement)
.FirstOrDefault(o => o.SomeProperty == SomeState);
child
không định nghĩa được.
@Bryce, câu trả lời thực sự tốt đẹp.
Phiên bản VB.NET:
Public Shared Iterator Function FindVisualChildren(Of T As DependencyObject)(depObj As DependencyObject) As IEnumerable(Of T)
If depObj IsNot Nothing Then
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(depObj) - 1
Dim child As DependencyObject = VisualTreeHelper.GetChild(depObj, i)
If child IsNot Nothing AndAlso TypeOf child Is T Then
Yield DirectCast(child, T)
End If
For Each childOfChild As T In FindVisualChildren(Of T)(child)
Yield childOfChild
Next
Next
End If
End Function
Cách sử dụng (điều này vô hiệu hóa tất cả các TextBox trong một cửa sổ):
For Each tb As TextBox In FindVisualChildren(Of TextBox)(Me)
tb.IsEnabled = False
Next
Tôi thấy nó dễ dàng hơn mà không cần Visual Tree Helpers:
foreach (UIElement element in MainWindow.Children) {
if (element is TextBox) {
if ((element as TextBox).Text != "")
{
//Do something
}
}
};