委托相关

委托:委托类似于我们的中介

什么时候用委托?当我们普通的调用无法实现的时候 ,就需要使用委托来实现 ,通过用于窗体与窗体之间 ,因为单个窗体没有使用的必要。

  • 举个例子 ,我们为什么需要找中介 ,肯定是我们没法获取方源

经典委托Delegate五步法

  1. 声明委托 ,类的外面 ,与类是同级的 , public delegate void ShowChildValueDelegate();

  2. 创建委托变量 ,在哪里调用就在哪里去创建 ,哪里调用要看数据在什么 ,动作源在哪里

    比如:private ShowChildValueDelegage ShowChildValue

  3. 创建委托方法:哪里实现就在哪里创建 ,明确参数和返回值 ,委托原型与委托方法要保持一致

    private void ShowValue(string value) {}
    
  4. 委托变量绑定委托方法:哪里可以实现绑定就在哪里绑定 ,什么地方可以获取到委托变量和委托方法

    1. = 赋值 ,+= 追加
    2. 单播委托:一个委托变量只需要或允许绑定一个方法 , = 赋值
    3. 多播委托:一个委托变量需要或可能绑定多个方法 , += 追加
    4. 例如:this.SowChildValue = frmChild.ShowValue
  5. 调用委托:希望在哪里调用就在哪里调用 ,如:this.SowChildValue(this.lbl_Temp.Text)

委托的遍历与删除应用

image

基于委托实现子窗体传值

一句话讲清楚
子窗体想把数据传回主窗体?别直接改主窗体的控件!用“委托+事件”——子窗体喊一声“我有数据了!”,主窗体听见后自己去拿。


1. 为什么用委托?(别跳过!)

  • ❌ 错误做法:在子窗体里直接写 主窗体.文本框.Text = "xxx"
    → 会报错、耦合高、代码乱成一锅粥。
  • ✅ 正确做法:子窗体只负责“通知”,主窗体自己“接收并处理”。
    → 安全、清晰、好维护。

2. 三步搞定(超简单)

第一步:在子窗体里定义“喊话工具”

在子窗体(比如叫 Form2)里写:

// 1. 声明一个委托(相当于定义“喊话”的格式)
public delegate void SendDataHandler(string msg);// 2. 声明一个事件(相当于“喇叭”)
public event SendDataHandler DataSent;

小白提示:这两行写在 public partial class Form2 : Form 里面,但别写在方法里!

第二步:子窗体“喊话”

比如点一个“确定”按钮时:

private void btnOK_Click(object sender, EventArgs e)
{// 3. 通过事件“喊话”,把数据传出去DataSent?.Invoke(textBox1.Text); // 把文本框内容喊出去this.Close(); // 关闭子窗体
}

?. 是安全调用:如果没人听(没订阅),就不喊,不会报错。

第三步:主窗体“监听并接收”

在主窗体(比如 Form1)打开子窗体的地方:

private void btnOpen_Click(object sender, EventArgs e)
{Form2 f2 = new Form2();// 4. 订阅事件:告诉子窗体“我听着呢!”f2.DataSent += F2_DataSent; f2.ShowDialog(); // 模态打开(等子窗体关了才继续)
}

然后写一个接收方法:

// 5. 这个方法会被自动调用,msg 就是传过来的数据
private void F2_DataSent(string msg)
{// 把数据放到主窗体的文本框里txtResult.Text = msg;
}

3. 完整代码结构(照着抄就行)

子窗体 Form2.cs

public partial class Form2 : Form
{// 1. 委托public delegate void SendDataHandler(string msg);// 2. 事件public event SendDataHandler DataSent;public Form2(){InitializeComponent();}private void btnOK_Click(object sender, EventArgs e){// 3. 喊话DataSent?.Invoke(textBox1.Text);this.Close();}
}

主窗体 Form1.cs

public partial class Form1 : Form
{public Form1(){InitializeComponent();}private void btnOpen_Click(object sender, EventArgs e){Form2 f2 = new Form2();f2.DataSent += F2_DataSent; // 4. 监听f2.ShowDialog();}private void F2_DataSent(string msg) // 5. 接收{txtResult.Text = msg;}
}

4. 小白常见问题

Q:为什么不能直接 Form1 f1 = new Form1(); f1.txt.Text = ...
A:你 new 出来的是新窗体,不是屏幕上那个!改了也看不到。

Q:DataSent?.Invoke(...)中的 ?是啥?
A:防止没人监听时报错。有订阅就喊,没订阅就安静。

Q:能不能传多个值?
A:可以!改委托就行:

public delegate void SendDataHandler(string name, int age);
DataSent?.Invoke("张三", 20);

接收方法也要对应改参数。


5. 记住这个套路

  1. 子窗体:定义委托 + 事件
  2. 子窗体:触发事件传数据
  3. 主窗体:订阅事件 + 写接收方法

搞定!不用记原理,先照着做,做两次就熟了。

多播委托传值多个子窗体

一句话讲明白
一个主窗体打开多个子窗体,每个子窗体都能传数据回来,而且互不干扰——用同一个委托事件,但每个子窗体独立触发,主窗体统一接收。


1. 什么是“多播委托”?

  • 委托可以“绑多个方法”,叫多播(Multicast)。
  • 但在窗体传值场景里,我们不是让一个事件触发多个方法,而是:
    多个子窗体各自触发同一个类型的事件,主窗体分别监听每个子窗体
  • 小白重点:每个子窗体都要单独订阅!

2. 实现目标

  • 主窗体有一个按钮,点一次开一个子窗体(可开多个)。
  • 每个子窗体有个输入框和“发送”按钮。
  • 点“发送”,把内容传回主窗体的列表框(ListBox)里。
  • 多个子窗体同时开着,各自传值互不影响。

3. 三步搞定(照着抄)

第一步:子窗体定义委托和事件(和单个一样)
// FormChild.cs(子窗体)
public partial class FormChild : Form
{// 1. 定义委托public delegate void DataSendHandler(string data);// 2. 定义事件public event DataSendHandler OnDataSend;public FormChild(){InitializeComponent();}private void btnSend_Click(object sender, EventArgs e){// 3. 触发事件,传出数据OnDataSend?.Invoke(txtInput.Text);// 注意:这里不关闭窗体!可以多次发送}
}

✅ 子窗体不关,方便多次传值。

第二步:主窗体打开多个子窗体,并分别订阅
// FormMain.cs(主窗体)
int childCount = 0; // 用来区分子窗体编号private void btnOpenChild_Click(object sender, EventArgs e)
{childCount++;FormChild child = new FormChild();// 4. 给每个子窗体单独订阅事件!child.OnDataSend += (data) =>{// 匿名方法:直接写处理逻辑listBox1.Items.Add($"子窗体{childCount}传回: {data}");};child.Text = $"子窗体 {childCount}"; // 设置标题方便区分child.Show(); // 用 Show(),不是 ShowDialog()
}

关键:每次 new 一个子窗体,都要重新订阅一次事件
childCount 区分是哪个子窗体传的。

第三步:运行效果
  • 点三次“打开子窗体” → 弹出三个窗体。
  • 在子窗体1输入“你好”,点发送 → 主窗体列表显示:“子窗体1传回: 你好”
  • 在子窗体3输入“测试”,点发送 → 显示:“子窗体3传回: 测试”

4. 完整代码(直接复制就能跑)

子窗体 FormChild.cs

public partial class FormChild : Form
{public delegate void DataSendHandler(string data);public event DataSendHandler OnDataSend;public FormChild(){InitializeComponent();}private void btnSend_Click(object sender, EventArgs e){OnDataSend?.Invoke(txtInput.Text);}
}

主窗体 FormMain.cs

public partial class FormMain : Form
{int childCount = 0;public FormMain(){InitializeComponent();}private void btnOpenChild_Click(object sender, EventArgs e){childCount++;FormChild child = new FormChild();// 匿名方法订阅,带编号标识int currentId = childCount; // 捕获当前编号(避免闭包问题)child.OnDataSend += (data) =>{listBox1.Items.Add($"子窗体{currentId}传回: {data}");};child.Text = $"子窗体 {childCount}";child.Show();}
}

⚠️ 注意:int currentId = childCount;​ 这行很重要!
如果直接用 childCount,所有子窗体都会显示最后一个编号(闭包陷阱)。


5. 小白避坑指南

问题 原因 解决
所有子窗体都显示“子窗体3” 闭包捕获的是变量引用,不是值 int currentId = childCount; 拷贝一份
点发送没反应 忘了订阅事件 每次 new 子窗体后必须 +=
只能传一次 用了 ShowDialog() 并且关窗了 Show(),别关窗
主窗体收不到数据 事件名写错 / 没触发 检查 OnDataSend?.Invoke(...) 是否执行

6. 能不能传复杂数据?

当然可以!比如传姓名+年龄:

// 委托改成
public delegate void DataSendHandler(string name, int age);// 子窗体触发
OnDataSend?.Invoke(txtName.Text, int.Parse(txtAge.Text));// 主窗体接收
child.OnDataSend += (name, age) =>
{listBox1.Items.Add($"{name}, {age}岁");
};

7. 记住这个模式

  • 子窗体:只管喊(触发事件)
  • 主窗体:谁喊我听谁(每个实例单独订阅)
  • 多个子窗体 = 多个独立实例 + 多次订阅

搞定!多播委托在窗体传值中,核心就是每个子窗体独立通信,不是“一个事件多人听”,而是“每人一个喇叭,主窗体全装上”。

系统委托Action简化Delegate

一句话总结
Action​ 是 C# 自带的“万能委托”,不用自己写 delegate,写起来更快、更干净!


1. 以前怎么写(麻烦版)

想让子窗体传个字符串回主窗体,以前得:

// 1. 先声明委托类型
public delegate void MyHandler(string msg);// 2. 再声明事件
public event MyHandler DataSent;// 3. 触发
DataSent?.Invoke("hello");

三行代码,其实就干一件事:传一个字符串


2. 现在怎么写(Action 简化版)

直接用系统自带的 Action<T>

// 1. 直接声明事件,不用写 delegate!
public event Action<string> DataSent;// 2. 触发方式完全一样
DataSent?.Invoke("hello");

✅ 少写一行代码
✅ 不用起名字(不用 MyHandler
✅ 功能完全一样!


3. Action 能传几个参数?

  • Action:无参数

    public event Action Clicked;
    Clicked?.Invoke();
    
  • Action<T>:1个参数

    public event Action<string> MessageSent;
    MessageSent?.Invoke("hi");
    
  • Action<T1, T2>:2个参数

    public event Action<string, int> UserInfoSent;
    UserInfoSent?.Invoke("张三", 25);
    
  • 最多支持 16 个参数(但别真写那么多!)

记住:Action 不能有返回值。要返回值用 Func<T>(以后再说)。


4. 子窗体传值实战(Action 版)

子窗体 Form2.cs

public partial class Form2 : Form
{// 直接用 Action<string>,不用自己定义 delegate!public event Action<string> DataSent;private void btnSend_Click(object sender, EventArgs e){DataSent?.Invoke(textBox1.Text); // 传值}
}

主窗体 Form1.cs

private void btnOpen_Click(object sender, EventArgs e)
{Form2 f2 = new Form2();// 订阅事件(写法不变)f2.DataSent += (msg) =>{textBox1.Text = msg;};f2.Show();
}

✅ 代码更短
✅ 逻辑更清晰
✅ 新手不容易写错


5. 对比:传统 delegate vs Action

写法 传统 delegate Action
声明委托 public delegate void Handler(string s); 不用声明
声明事件 public event Handler MyEvent; public event Action<string> MyEvent;
触发 MyEvent?.Invoke("x"); MyEvent?.Invoke("x");
代码行数 多1行 少1行
易错点 名字写错、重复定义 几乎不会错

6. 小白注意事项

  • Action 适合“只传数据,不需要返回” 的场景(比如窗体传值、按钮点击通知)。

  • 不能用 Action 返回值。比如想让子窗体问主窗体“要不要保存?”,主窗体返回 true/false —— 这时候用 Func<bool>

  • Action 是 .NET 内置的,不用 using,直接用。

  • 记住常用形式

  • Action → 无参

  • Action<string> → 传一个字符串

  • Action<string, int> → 传字符串和数字


7. 一句话口诀

传数据不用返回?直接上 Action<T>
别再手写 delegate,系统给你准备好!

搞定!从此写委托,又快又稳不翻车。

系统委托带返回值Func应用

一句话讲清楚
Action​ 只能“发消息”,不能“要答案”;
Func​ 能“问问题 + 拿结果”,比如:“主窗体,这个用户名能用吗?”,主窗体回答 true​ 或 false


1. Func 是啥?和 Action 有啥区别?

Action Func
作用 执行动作,无返回值 执行动作,有返回值
例子 发送消息、通知关闭 验证数据、获取配置、计算结果
写法 Action<string> Func<string, bool>
返回值 ❌ 没有 ✅ 最后一个类型就是返回值!

Func 的最后一个泛型参数 = 返回值类型
比如:Func<int, string, bool>​ 表示:传一个 int​ 和一个 string​,返回 bool


2. 最常用写法(记住这3个够用)

Func<bool>                 // 无参数,返回 bool
Func<string, bool>         // 传 string,返回 bool
Func<string, int, string>  // 传 string + int,返回 string

3. 实战场景:子窗体问主窗体“用户名是否重复?”

需求
子窗体输入用户名 → 点“检查” → 主窗体判断是否已存在 → 返回 true/false

第一步:子窗体定义 Func 委托字段(不是事件!)
// FormChild.cs
public partial class FormChild : Form
{// 注意:这里用字段,不是 event!因为要调用并拿返回值public Func<string, bool> CheckUsername;private void btnCheck_Click(object sender, EventArgs e){string input = txtUsername.Text;// 调用主窗体的方法,并拿到返回值!if (CheckUsername != null){bool isExist = CheckUsername(input);lblResult.Text = isExist ? "已存在" : "可用";}}
}

⚠️ 重点:用字段(Field)或属性(Property),不能用 event
因为事件不能直接调用拿返回值!

第二步:主窗体赋值给这个 Func
// FormMain.cs
private void btnOpenChild_Click(object sender, EventArgs e)
{FormChild child = new FormChild();// 把主窗体的验证方法“塞给”子窗体child.CheckUsername = IsUsernameExist;child.Show();
}// 主窗体的验证方法(返回 bool)
private bool IsUsernameExist(string username)
{// 模拟数据库检查List<string> existNames = new List<string> { "admin", "root", "test" };return existNames.Contains(username);
}

✅ 子窗体调用 CheckUsername("admin")​ → 主窗体执行 IsUsernameExist("admin")​ → 返回 true


4. 匿名方法 / Lambda 写法(更简洁)

主窗体也可以不写单独方法,直接用 Lambda:

child.CheckUsername = (name) =>
{return name == "admin" || name == "guest";
};

或者更短:

child.CheckUsername = name => name == "admin";

5. 常见错误 & 小白避坑

错误 原因 正确做法
event Func<...> 事件不能获取返回值 用普通字段或属性
忘记判空 if (CheckUsername != null) 没赋值就调用会报错 调用前先判空
返回值类型写错 比如写成 Func<string> 但方法返回 int 确保方法返回类型和 Func 最后一个泛型一致

6. 对比:Action vs Func 使用场景

  • 用 Action
    “主窗体,我关了!”
    “主窗体,用户点了保存!”
    → 只通知,不需要回答。
  • 用 Func
    “主窗体,这个ID存在吗?” → 要 true/false
    “主窗体,给我配置路径!” → 要 string
    → 需要返回结果。

7. 一句话口诀

要返回值?用 Func
最后一个泛型是答案,前面全是问题参数。
别用 event,直接赋方法!

搞定!从此“问问题+拿答案”,轻松搞定双向交互。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/922577.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

音乐视频怎么做mp3下载网站wordpress输出文章标签名

有一个很简单的办法u-boot编译结束时&#xff0c;会在tool文件夹下面生成一个mkimage文件&#xff0c;将这个文件复制到交叉编译器目录下的bin文件夹下面&#xff0c;以后编译时就会生成uImage文件&#xff0c;省的用命令行的方式转了&#xff1b;另外将采用命令行的方式也贴出…

html5和php做网站网站导航作用

K线实战分析系列之二十二&#xff1a;圆形顶部和圆形底部形态 一、圆形顶部形态二、圆形顶部和圆形底部形态的总结 一、圆形顶部形态 市场多空一方被逐渐击退&#xff0c;跳空的缺口是一方突然发力&#xff0c;体现出一方对市场掌握了控制权 二、圆形顶部和圆形底部形态的总结…

深圳网站设计服务公网站 数据库 sql 导入数据库文件

目录 1.由正规式到DFA 首先讲如何从正规式到NFA 如何从NFA到DFA 2.DFA的化简 3.DFA和NFA的区别 1.由正规式到DFA 正规式--->NFA---->DFA 首先讲如何从正规式到NFA 转换规则: 例题1&#xff1a;这里圆圈里面的命名是随意的&#xff0c;只要能区别开就可以了 如何…

廊坊网站群发关键词精品课程网站建设内容

本项目并非 Google 官方项目, 而是由国内程序员凭热情创建和维护。 如果你关注的是 Google 官方英文版, 请移步 Google Style Guide 以下代码中 Yes 表示推荐&#xff0c;No 表示不推荐。 文章目录 分号行长度括号缩进空行空格Shebang注释类字符串文件和 socketsTODO 注释导入…

企业网站备案 名称温州品牌设计公司

据新闻报道&#xff0c;5月25日&#xff0c;安徽黄山景区内发生雷击&#xff0c;闪电击中飞来石景点的护栏&#xff0c;多人被碎石砸中受伤。景区工作人员表示&#xff0c;飞来石附近本就属于雷区&#xff0c;当天曾发过两次雷电预警。 随着旅游业的繁荣发展&#xff0c;越来越…

做一个网站需要哪些中国建筑装饰网网址

博客 https://songxwn.com/Pigsty-PG-RDS/ 简介 Pigsty 是一个更好的本地自建且开源 RDS for PostgreSQL 替代&#xff0c;具有以下特点&#xff1a; 开箱即用的 PostgreSQL 发行版&#xff0c;深度整合地理、时序、分布式、图、向量、分词、AI等 150 余个扩展插件&#xff…

国际型网站建设战略网页游戏开服表

目录 一、网络爬虫中的正则表达式和re模块&#xff08;一&#xff09;数据提取的精确性&#xff08;二&#xff09;处理复杂的文本结构&#xff08;三&#xff09;提高数据处理效率 二、正则表达式的内涵&#xff08;一&#xff09;、常用元字符&#xff08;二&#xff09;、量…

购物网站开发的需求分析网站建设栏目添加

一、调用位置 在理解this的绑定过程之前&#xff0c;首先要理解调用位置&#xff1a;调用位置就是函数在代码中被调用的位置&#xff08;而不是申明的位置&#xff09;。只有仔细分析调用位置才能回答这个问题&#xff1a;这个this到底引用的是什么&#xff1f; function foo…

游戏平台网站开发宁波高端网站建设

作者 | 阿丸笔记责编 | 徐威龙封图| CSDN 下载于视觉中国在网上看过很多HBaes架构相关的文章&#xff0c;内容深浅不一&#xff0c;直到发现了一篇MapR官网的文章&#xff0c;写得实在太生动了。https://mapr.com/blog/in-depth-look-hbase-architecture/#.VdMxvWSqqko&#xf…

小网站搜什么关键词好网页制作格式

人工神经网络文献综述 摘要 人工神经网络&#xff08;Artificial Neural Networks, ANNs&#xff09;是由多个简单的、相互连接的处理单元组成的自适应系统&#xff0c;通过调整这些单元之间的连接强度&#xff0c;ANNs能够实现对复杂数据的建模和预测。本文综述了ANNs的基本…

金融投资网站源码棉花数据检验与加工平台

—————————————————————————————————— 一、函数依赖的推理规则&#xff1a; 1、自反律&#xff1a;若Y⊆X⊆U&#xff0c;则X→Y在R上成立。 2、增广律&#xff1a;若X→Y在R上成立&#xff0c;且Z⊆U&#xff0c;则XZ→YZ在R上也成立。 3、传…

做动画人设有哪些网站可以借鉴邯郸信息网平台

『youcans 的 OpenCV 例程200篇 - 总目录』 【youcans 的 OpenCV 例程200篇】25. 图像的平移 平移是物体位置在水平和垂直方向的移动。 像素点 (x,y) 沿 x 轴平移 dx、沿 y 轴平移 dy&#xff0c;可以由以下公式描述&#xff1a; [x~y~1]MAT[xy1],MAT[10dx01dy001]\begin{bmat…

做网站找那些公司如何在阿里云部署网站

第六部分、数据结构树&#xff0c;树存储结构详解 数据结构的树存储结构&#xff0c;常用于存储逻辑关系为 "一对多" 的数据。 树存储结构中&#xff0c;最常用的还是二叉树&#xff0c;本章就二叉树的存储结构、二叉树的前序、中序、后序以及层次遍历、线索二叉树、…

网站优化人员网站名称和备案不一样

一、问题 先用conda指令创建了python3.10的环境&#xff0c;然后在IDEA或Pycharm里添加Python解释器环境报Cannot set up a python SDK的错误&#xff0c; 二、解决方法 发现在默认创建新环境选择Python版本时只能选择&#xff1a;2.7&#xff0c;3.6&#xff0c;3.7&#xff…

莞城仿做网站竞价代运营

文章目录 ps -axj&#xff1a;查看进程ps -aL&#xff1a;查看线程echo $?&#xff1a;查看最近程序的退出码jobs&#xff1a;查看后台运行的线程组fd 任务号&#xff1a;将后台任务提到前台bg 任务号&#xff1a;将暂停的后台程序重启netstat -nltp&#xff1a;查看服务及监听…

滕州市东方建设工程事务有限公司网站中英繁网站源码

执笔 | 姜 姜 编辑 | 古利特 刚刚站上300亿元新台阶&#xff0c;泸州老窖再次传来喜讯。 <<<左右滑动查看更多>>> 4月28日&#xff0c;四川省庆祝“五一”国际劳动节大会在成都召开。泸州老窖股份有限公司工业4.0项目秘书长赵丙坤、泸州老窖酿酒有限责任公…

成都电子商城网站开发核酸检测收费

作者 | 宋慧出品 | CSDN云计算&#xff08;ID&#xff1a;CSDNcloud&#xff09;关于数据中台的问题&#xff0c;CSDN 在一年前采访了 Gartner 研究总监孙鑫&#xff0c;采访中&#xff0c;孙鑫提到 数据分析将是改变“游戏规则”的技术、企业的中台需要可组装的架构 。经过一年…

兰州最好的网站建设公司呼和浩特百度seo

IDEA刷新项目&#xff0c;报错[ERROR] Malformed \uxxxx encoding. 现象 1.控制台报错 [ERROR] Malformed \uxxxx encoding.2.项目代码大部分爆红 3.Pom文件不爆红 4.IDEA未能构建Dependencies 尝试清除IDEA缓存无效&#xff0c;重新克隆项目无效&#xff0c;更换低版本mav…

Java 与智慧港口:航运调度与物流枢纽数字化

一、引言 港口是全球贸易的重要枢纽,承担着 货物集散、航运调度、物流中转 的关键作用。随着全球化和电商的快速发展,港口面临 货流量暴增、作业效率不足、调度复杂、安全监管难度大 等挑战。智慧港口的目标是:通过…

自己做报名网站教程品牌网站如何做

1&#xff0c;docker简介 docker主要解决了最初软件开发环境配置的困难&#xff0c;完善了虚拟机部署的资源占用多&#xff0c;启动慢等缺点&#xff0c;保证了一致的运行环境&#xff0c;可以更轻松的维护和扩展。docker在linux容器的基础上进行了进一步的封装&#xff0c;提…