2013年(21)
分类: C#/.net
2013-08-20 15:21:04
WPF - Find Child Control by name in WPF way
Topic: WPF - Find Child Control by name in WPF way
标题: WPF – wpf方式按名字查找子控件
我们知道windows API 暴露了一个自动化接口,该接口允许你按名字查找控件,但是为了创建一个好的工具函数,我们可以使用VisualTreeHelper列举Visual Tree以按照WPF方式按名和类型找到子控件。
We know that Windows API may has exposed some automation API that allows you to find one control by its name, while to make a good utility method, we can use the VisualTreeHelper to iterate through the Visual Tree to get the named Child control and its type.
找到工具类/方法如下
The Utility class/method that we making of is now .
public static class VisualTreeHelperUtilities
{
///
/// Finds a Child of a given item in the visual tree.
///
/// A direct parent of the queried item.
///
/// x:Name or Name of child.
///
/// If not matching item can be found,
/// a null parent is being returned.
public static T
FindChild
where T : System.Windows.DependencyObject
{
// confirm parent and childName are valid
if (parent == null) return null;
T foundChild = null;
int childrenCount = System.Windows.Media.VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = System.Windows.Media.VisualTreeHelper.GetChild(parent, i);
// if hte child is not the requested child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild
// if the child is Found, break so we don't overwrite the found child
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as System.Windows.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;
}
}
方便测试,我们创建了如下的View Model
To make an test, here is the view model code that we created.
public class MainWindowViewModel : INotifyPropertyChanged
{
#region Instance Fields
private string _childNameToFound;
private Type _childType;
private FrameworkElement _foundChild;
private DependencyObject _parent;
#endregion
#region Construction and Initialization
public MainWindowViewModel(MainWindow mainwindow)
{
_parent = mainwindow;
}
#endregion
#region Properties
public string ChildNameToFound
{
get
{
return _childNameToFound;
}
set
{
_childNameToFound = value;
RaisePropertyChanged("ChildNameToFound");
FindChildByName();
}
}
public Type ChildType
{
get
{
return _childType;
}
set
{
_childType = value;
RaisePropertyChanged("ChildType");
FindChildByName();
}
}
public FrameworkElement FoundChild
{
get
{
return _foundChild;
}
set
{
_foundChild = value;
RaisePropertyChanged("FoundChild");
}
}
internal DependencyObject Parent
{
get
{
return _parent;
}
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (propertyName == string.Empty) throw new ArgumentException("string.Empty is not allowed");
if (propertyName == null) throw new ArgumentNullException("propertyName");
PropertyChangedEventHandler propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Find Child by name
private void FindChildByName()
{
var childName = ChildNameToFound;
if (ChildType == typeof(ListBox))
{
FoundChild = VisualTreeHelperUtilities.FindChild
}
else if (ChildType == typeof(TextBox))
{
FoundChild = VisualTreeHelperUtilities.FindChild
}
else if (ChildType == typeof(TextBlock))
{
FoundChild = VisualTreeHelperUtilities.FindChild
}
else if (ChildType == typeof(ComboBox))
{
FoundChild = VisualTreeHelperUtilities.FindChild
}
}
#endregion
}
View Model 是按照如下的方法连接到MainWindow上的。
The view model is thus wired up to the MainWindow (the view) as such..
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel(this);
}
}
如下是我们该怎么定义这个View的。
Here comes how we define the view.
xmlns=""
xmlns:x=""
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow"
Height="350" Width="525">
x:Name="ChildNameToFoundText"
Text="{Binding ChildNameToFound}"
Grid.Row="0"
Visibility="Collapsed"
/>
x:Name="ChildNameToFound"
Grid.Row="0"
SelectedItem="{Binding ChildNameToFound, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
x:Name="ChildType"
Grid.Row="1"
SelectedItem="{Binding ChildType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
x:Name="FoundChild"
Text="{Binding FoundChild}"
Grid.Row="2"
>
程序开始的时候,你得到如下的
When the program start, here is what you get.
引用:
References: