图片 5

C# WPF 通过委托实现多窗口间的传值

Posted by

在使用WPF开发的时候就不免会遇到需要两个窗口间进行传值操作,当然多窗口间传值的方法有很多种,本文介绍的是使用委托实现多窗口间的传值。

简介

  本文将完整叙述我利用VisualTreeHelper实现题述功能的全部过程,想直接看函数实现的朋友可以跳到函数实现部分。 
  或者直接在GitHub上下载源码。 
   
  在WPF中我们经常会遇到这种情况:当我们尝试着去寻找窗体或者页面中某个控件的子控件或者父控件的时候,我们只能寻找到它的第一级的逻辑子级对象或者父级对象。当我们想更深入的时候,就没有办法了。 
  甚至在我们自定义的DataTemplate中的控件,我们都没办法对其访问。比如在ListView中自定义的控件,我们就没办法获取指定位置的控件了。相关例子可以参见我的博文: WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探 。 
  本文将探讨解决方案。

在上代码之前呢,先简单介绍一下什么是C#中的委托(如果只想了解如何传值可以略过这部分)在网络上有很多对于委托的介绍和讲解,经过我的学习和总结加上了一点我自己的理解,我认为委托是一种类似于C语言的指针,但是它指向的是方法而不是变量。如果把委托看作一个变量,那么这个变量里存着的就是你目标方法的地址,调用委托约等于调用你的目标方法。(个人理解欢迎指正交流)

VisualTreeHelper

  微软在VisualTreeHelper类中,提供了一些实用工具方法,用于执行涉及可视化树中的节点的常规任务,VisualTreeHelper
类中的一些方法可以接受表示任意一种可视对象类型的 DependencyObject
值。 
  这里我们将要用到两个方法分别是:VisualTreeHelper.GetChild()和VisualTreeHelper.GetParent()。

 

使用VisualTreeHelper

以下正文:

模拟场景搭建

  新建一个WPF工程,命名为VisualTreeHelperDemo。 
  假设我们有如下如所示的一个主窗体,窗体的内容容器为一个name=”TopGrid”的Grid控件,它包含了上下两个子级Grid,每个子级Grid中各自包含了一个Button。 
  图片 1 
  MainWindow.xaml代码如下:  

 1 <Window x:Class="VisualTreeHelper.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         Title="MainWindow" Height="350" Width="525">
 5     <Grid Name="TopGrid">
 6         <Grid.RowDefinitions>
 7             <RowDefinition></RowDefinition>
 8             <RowDefinition></RowDefinition>
 9         </Grid.RowDefinitions>
10         <Grid >
11             <Button Content="Button1" Name="btn_One" VerticalAlignment="Center" HorizontalAlignment="Center">
12             </Button>
13         </Grid>
14         <Grid  Grid.Row="1">
15             <Button Content="Button2" Name="btn_Two" VerticalAlignment="Center" HorizontalAlignment="Center">
16             </Button>
17         </Grid>
18     </Grid>
19 </Window>

实现窗口间的相互传值,先创建两个窗口,先上代码主窗口代码:

遍历寻找子级对象

  现在我们来寻找TopGrid所有Button子级对象,并输出它们的名称。 
  打开MainWindow.xaml.cs文件,添加寻找子级对象的代码如下:

 1 /// <summary>
 2 /// 利用visualtreehelper寻找对象的子级对象
 3 /// </summary>
 4 /// <typeparam name="T"></typeparam>
 5 /// <param name="obj"></param>
 6 /// <returns></returns>
 7 List<T> FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
 8 {
 9     try
10     {
11         List<T> TList = new List<T> { };
12         for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
13         {
14             DependencyObject child = VisualTreeHelper.GetChild(obj, i);
15             if (child != null && child is T)
16             {
17                 TList.Add((T)child);
18                 List<T> childOfChildren = FindVisualChild<T>(child);
19                 if (childOfChildren != null)
20                 {
21                     TList.AddRange(childOfChildren);
22                 }
23             }
24             else
25             {
26                 List<T> childOfChildren = FindVisualChild<T>(child);
27                 if (childOfChildren != null)
28                 {
29                     TList.AddRange(childOfChildren);
30                 }
31             }
32         }
33         return TList;
34     }
35     catch (Exception ee)
36     {
37         MessageBox.Show(ee.Message);
38         return null;
39     }
40 }

 在btn_One_Click事件里面书写代码如下:

 

 1 /// <summary>
 2 /// 窗体加载事件
 3 /// </summary>
 4 /// <param name="sender"></param>
 5 /// <param name="e"></param>
 6 private void btn_One_Click(object sender, RoutedEventArgs e)
 7 {
 8     string btnName = "";
 9     List<Button> btnList = FindVisualChild<Button>(TopGrid);
10     foreach (Button item in btnList)
11     {
12         btnName += string.IsNullOrEmpty(btnName) ? item.Name.ToString() : "," + item.Name.ToString();
13     }
14     Show(string.Format(TopGrid.Name.ToString()+"共有{0}个Button,名称分别为{1}", btnList.Count, btnName));
15 }

 

运行程序,点击Button1,结果如下图: 

 
  图片 2 
   
  结果表明遍历成功。 

 

MainWindow.xaml

遍历寻找父级对象

  现在我们来遍历Button2的父级对象,获得其所有父级对象的信息,并且展示。 
  打开MainWindow.xaml.cs文件,添加寻找父级对象的代码如下:

 1 /// <summary>
 2 /// 利用VisualTreeHelper寻找指定依赖对象的父级对象
 3 /// </summary>
 4 /// <typeparam name="T"></typeparam>
 5 /// <param name="obj"></param>
 6 /// <returns></returns>
 7 public static List<T> FindVisualParent<T>(DependencyObject obj) where T : DependencyObject
 8 {
 9     try
10     {
11         List<T> TList = new List<T> { };
12         DependencyObject parent = VisualTreeHelper.GetParent(obj);
13         if (parent != null && parent is T)
14         {
15             TList.Add((T)parent);
16             List<T> parentOfParent = FindVisualParent<T>(parent);
17             if (parentOfParent !=null)
18             {
19                 TList.AddRange(parentOfParent);
20             }
21         }
22         else if ( parent != null )
23         {
24              List<T> parentOfParent = FindVisualParent<T>(parent);
25              if (parentOfParent != null)
26              {
27                  TList.AddRange(parentOfParent);
28              }
29         }
30         return TList;
31     }
32     catch (Exception ee)
33     {
34         MessageBox.Show(ee.Message);
35         return null;
36     }
37 }

在btn_Two_Click中添加代码如下:

 

 1 /// <summary>
 2 /// 遍历Button2父级对象信息
 3 /// </summary>
 4 /// <param name="sender"></param>
 5 /// <param name="e"></param>
 6 private void btn_Two_Click(object sender, RoutedEventArgs e)
 7 {
 8     string parentName = "";
 9     List<Grid> gridList = FindVisualParent<Grid>(btn_Two);
10     foreach (Grid item in gridList)
11     {
12         parentName += string.IsNullOrEmpty(parentName) ? item.Name.ToString() : "," + item.Name.ToString();
13     }
14     MessageBox.Show(string.Format(btn_Two.Name.ToString() + "共有{0}个逻辑父级,名称分别为{1}", gridList.Count, parentName));
15 }

 

运行程序,点击Button2,效果如下: 
图片 3 
  结果表明遍历成功。

<Grid>
  <TextBox Name="MainWindowTextBox" HorizontalAlignment="Left" Height="23" Margin="10,61,0,0" TextWrapping="Wrap" Text="空" VerticalAlignment="Top" Width="297"/>
  <Button Content="打开新窗口" HorizontalAlignment="Left" Margin="10,130,0,0" VerticalAlignment="Top" Width="297" Click="ButtonBase_OnClick"/>
</Grid>

总结

  通过上述的方法我们就可以随心所欲地获取我们想要的控件对象,并对其进行操作,包括自定义的DataTemplate中的控件都可以获取。

 

 MainWindow.xaml.cs

 1 public void GetValue(string value1, TextBox value2)
 2   {
 3     MainWindowTextBox.Text = value1;
 4   }
 5 
 6 private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
 7   {
 8     Window1 newWindow1 = new Window1();
 9     newWindow1.getTextHandler = GetValue;          //将方法赋给委托对象
10     newWindow1.ShowDialog();
11 
12   }

 

效果图如下:

图片 4

第二个窗口Window1代码:

Window1.xaml

<Grid>
    <TextBox Name="Window1TextBox" HorizontalAlignment="Left" Height="23" Margin="84,73,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
    <Button Content="传值" HorizontalAlignment="Left" Margin="84,125,0,0" VerticalAlignment="Top" Width="120" Click="ButtonBase_OnClick"/>
</Grid>

 Window1.xaml.cs

1 public delegate void GetTextHandler(string value1, TextBox value2);  //声明委托
2 public GetTextHandler getTextHandler;                                //委托对象
3 
4 private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
5   {
6     getTextHandler(Window1TextBox.Text, Window1TextBox);
7   }

效果图:

图片 5

实现效果当运行程序后,点击打开新窗口按钮后,会打开Window1窗口,在Window1窗口的Textbox中输入内容,点击传值,你所输入的内容就会传到主窗口,通过委托的事件将主窗口中的Textbox控件的内容更改为你传过去的值。效果如下:

相关文章

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注