在WPF应用程序开发中,经常需要在用户控件(UserControl)与父控件之间进行交互。例如,当用户在用户控件中点击一个按钮或展开一个扩展器(Expander)时,可能需要在父控件中做出响应。本文将介绍一种实现这种交互的方法,通过一个具体的示例,展示如何使用Expander控件在用户控件中触发事件,并由父控件处理。
目标是实现一个父控件,它包含一个ScrollViewer,里面放置了一个StackPanel。在StackPanel中,有一个ItemsControl,它的ItemTemplate是一个用户控件类型,绑定到ItemsControl.ItemsSource。当用户展开其中一个子Expander时,该用户控件会触发一个事件,父控件会捕获这个事件并处理子集合。问题在于StackPanel的子集合是一个ItemsControl,需要从中获取Expanders。
用户控件myTema基本上是一个Expander,其中包含一些消耗绑定数据的元素(在例子中,是一个HeaderTemplate和一些不需要的嵌套用户控件),以及一个绑定到Expanded事件的动作:
<Grid x:Name="LayoutRoot">
<toolkit:Expander x:Name="ExpanderTema" Expanded="ExpanderTema_Expanded" HeaderTemplate="{StaticResource ExpanderTemaDataTemplate}" Header="{Binding myTema_Conteudo, ElementName=myTemaRoot}">
<StackPanel x:Name="stackSugest">
</StackPanel>
</toolkit:Expander>
</Grid>
在C#中,定义了一个事件ExpanderTemaExpanded,并在ExpanderTema_Expanded方法中触发该事件:
public event EventHandler ExpanderTemaExpanded;
private void ExpanderTema_Expanded(object sender, System.Windows.RoutedEventArgs e)
{
ExpanderTemaExpanded?.Invoke(sender, null);
}
父控件的ItemsControl.ItemsSource基于一个本地变量,并捕获其任何用户控件子项的ExpanderTemaExpanded事件。
List<myTema_Info> ListTema = new List<myTema_Info>();
itemsMyTemas.ItemsSource = ListTema;
<ScrollViewer x:Name="ScrollViewer1">
<Grid>
<StackPanel x:Name="stackMyTemas">
<ItemsControl x:Name="itemsMyTemas">
<ItemsControl.ItemTemplate>
<DataTemplate>
<componente:myTema x:Name="myCategory_Temas" ExpanderTemaExpanded="myCategory_Temas_ExpanderTemaExpanded" myTema_Conteudo="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</ScrollViewer>
在由用户控件调用的方法中,ExpanderTemaExpanded事件是处理的核心,其中使用了GetAllChildFrameworkElement函数,该函数在下一节中解释。
private void myCategory_Temas_ExpanderTemaExpanded(object sender, System.EventArgs e)
{
var found = Tools.GetAllChildFrameworkElement(stackMyTemas, typeof(Expander));
foreach (Expander item in found)
{
if (item != (Expander)sender)
{
item.IsExpanded = false;
}
}
}
在案例中,使用了一个通用静态类,其中包含了所有通用函数,如在父StackPanel子集合中查找所有Expander所需的函数。
public static class Tools
{
public static List<FrameworkElement> GetAllChildFrameworkElement(FrameworkElement parentElement, Type typeRequired)
{
List<FrameworkElement> childFrameworkElementFound = new List<FrameworkElement>();
SearchAllChildFrameworkElement(parentElement, childFrameworkElementFound, typeRequired);
return childFrameworkElementFound;
}
private static void SearchAllChildFrameworkElement(FrameworkElement parentFrameworkElement, List<FrameworkElement> allChildFrameworkElement, Type typeRequired)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(parentFrameworkElement);
if (childrenCount > 0)
{
for (int i = 0; i < childrenCount; i++)
{
FrameworkElement childFrameworkElement = (FrameworkElement)VisualTreeHelper.GetChild(parentFrameworkElement, i);
if (childFrameworkElement.GetType().Equals(typeRequired))
{
allChildFrameworkElement.Add(childFrameworkElement);
}
SearchAllChildFrameworkElement(childFrameworkElement, allChildFrameworkElement, typeRequired);
}
}
}
}