Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
1h 9m 13s
C# 中的事件是一个基本概念,许多开发人员都在使用,但可能并没有完全理解,尤其是在创建自己的事件时。 Tim Corey 在他的视频" C# 事件 - 在应用程序中创建和使用事件"中提供了关于如何创建和使用事件的全面指南,探讨了最佳实践和高级功能。
在本文中,我们将探讨 C# 事件,重点介绍它们的语法、定义方式以及如何使用 Tim Corey 的视频示例来帮助解决常见的编程问题。 理解 C# 中的事件处理对于构建响应式应用程序至关重要,本文将帮助您掌握自定义错误日志记录、异常处理和事件驱动编程的核心概念。
在 C# 和其他编程语言中,事件在事件驱动编程中起着至关重要的作用,使应用程序能够响应用户交互或系统更改等操作。 与其他编程语言相比,C# 提供了一种结构化的事件处理方法,使其成为快速小型应用程序的理想选择。 C# 中的事件由特定操作触发,这些操作会调用相应的事件处理程序来执行所需的任务。
Tim 首先解释说,大多数开发人员都熟悉 C# 中的事件,但可能不知道如何创建自定义事件。 该视频的目标是介绍事件,逐步讲解如何创建自定义事件,讨论其功能,并概述最佳实践。
Tim 使用一个用 Windows Forms (WinForms) 构建的简单银行应用程序来演示事件。 该应用程序模拟一位客户的基本银行操作,包括查看余额和记录交易。
1.应用概述:
2.主要形式:
3.交易表格:
Tim 解释了演示银行应用程序的后端代码:
1.客户类别:
2.账户类别:
3.处理存款和付款:
4.透支保护:
有关代码示例,您可以直接参考 Tim Corey 的视频,他在 3:18 到 18:27 处解释了代码。
在本节中,Tim Corey 深入探讨了 Windows Forms 中按钮点击事件的工作原理,解释了这些事件是如何连接的以及它们是如何工作的。
Tim 首先解释了 Windows 窗体应用程序中按钮单击事件这一常见概念。 在设计器中双击按钮时,Visual Studio 会自动为单击事件生成事件处理程序方法。
1.事件处理方法:
private void recordTransactionButton_Click(object sender, EventArgs e)
{
// Code to handle the button click event
}
2.活动筹备:
this.recordTransactionButton.Click += new System.EventHandler(this.recordTransactionButton_Click);AddHandler Me.recordTransactionButton.Click, AddressOf Me.recordTransactionButton_ClickTim 解释了如何在 C# 中创建自定义事件,首先从 Account 类开始,事件将在该类中触发。
1.定义事件:
public event EventHandler<string> RaiseTransactionApprovedEvent;Public Event RaiseTransactionApprovedEvent As EventHandler(Of String)2.触发事件:
this)和事件数据(在这种情况下是一个字符串)。private void OnTransactionApproved(string transactionName)
{
RaiseTransactionApprovedEvent?.Invoke(this, transactionName);
}
3.连接和处理事件:
account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent;
private void Account_RaiseTransactionApprovedEvent(object sender, string e)
{
// Code to handle the event
}
Tim 解释了如何使用事件在发生某些操作时(例如交易获得批准时)自动更新浏览器 UI。
1.筹款活动:
public void AddDeposit(decimal amount, string depositName)
{
// Code to add deposit
RaiseTransactionApprovedEvent?.Invoke(this, depositName);
}
2.在用户界面中订阅事件:
public MainForm()
{
InitializeComponent();
account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent;
}
private void Account_RaiseTransactionApprovedEvent(object sender, string e)
{
// Update the UI with the new transaction
}
Tim Corey 解释了在 C# 中引发事件时如何使用 ?.Invoke() 语法。 这种现代方法简化了代码并确保了线程安全。
Invoke 前面的问号(?.)是空条件运算符。 它会在调用事件处理程序之前检查它是否为空,从而防止出现潜在的异常。
1.传统方法:
if (RaiseTransactionApprovedEvent != null)
{
RaiseTransactionApprovedEvent(this, depositName);
}
2.使用 ?.Invoke() 的现代方法:
RaiseTransactionApprovedEvent?.Invoke(this, depositName);RaiseTransactionApprovedEvent?.Invoke(Me, depositName)RaiseTransactionApprovedEvent为null,则调用不会继续,从而有效地避免了任何异常。3.益处:
-简化代码:减少安全调用事件所需的代码量。 -线程安全:通过检查空值并在一步中调用事件来消除竞争条件。
Tim 讲解了如何在 Windows 窗体应用程序中监听自定义事件并相应地更新 UI。
1.订阅活动:
customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;AddHandler customer.CheckingAccount.TransactionApprovedEvent, AddressOf CheckingAccount_TransactionApprovedEvent2.事件处理方法:
private void CheckingAccount_TransactionApprovedEvent(object sender, string e)
{
// Update the UI with the new transaction
checkingTransactionsDataSource.DataSource = null;
checkingTransactionsDataSource.DataSource = customer.CheckingAccount.Transactions;
checkingBalanceLabel.Text = customer.CheckingAccount.Balance.ToString("C2");
}
Tim 实际演示了创建、发起和处理自定义事件的整个过程。
1.触发事件:
private void OnTransactionApproved(string transactionName)
{
RaiseTransactionApprovedEvent?.Invoke(this, transactionName);
}
2.处理多个事件:
public MainForm()
{
InitializeComponent();
customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;
customer.SavingsAccount.TransactionApprovedEvent += SavingsAccount_TransactionApprovedEvent;
}
private void SavingsAccount_TransactionApprovedEvent(object sender, string e)
{
// Update the UI with the new savings transaction
savingsTransactionsDataSource.DataSource = null;
savingsTransactionsDataSource.DataSource = customer.SavingsAccount.Transactions;
savingsBalanceLabel.Text = customer.SavingsAccount.Balance.ToString("C2");
}
3.运行应用程序:
Tim 展示了如何调试事件并检查随事件发送的信息。
1.设置断点:
private void CheckingAccount_TransactionApprovedEvent(object sender, string e)
{
// Breakpoint here
}
2.调试:
Tim Corey 在演示的基础上,创建了另一个自定义事件来处理透支情况。 当发生透支时,此事件将被触发,并通知用户透支金额。
Tim 首先在 Account 类中定义了一个用于透支场景的新事件:
1.事件声明:
public event EventHandler<decimal> OverdraftEvent;Public Event OverdraftEvent As EventHandler(Of Decimal)2.触发事件:
if (overdraftSuccessful)
{
OverdraftEvent?.Invoke(this, overdraftAmount);
}
1.活动筹备:
customer.CheckingAccount.OverdraftEvent += CheckingAccount_OverdraftEvent;AddHandler customer.CheckingAccount.OverdraftEvent, AddressOf CheckingAccount_OverdraftEvent2.事件处理:
private void CheckingAccount_OverdraftEvent(object sender, decimal e)
{
errorMessage.Text = $"You had an overdraft protection transfer of {e:C2}";
errorMessage.Visible = true;
}
3.触发和显示事件:
You had an overdraft protection transfer of $20.44
蒂姆解释了如何用多种语言和形式收听同一事件,展示了事件的多样性。
1.向另一个表单添加标签:
<asp:Label ID="errorMessage" runat="server" Visible="false" />
2.订阅活动:
customer.CheckingAccount.OverdraftEvent += SecondaryForm_OverdraftEvent;AddHandler customer.CheckingAccount.OverdraftEvent, AddressOf SecondaryForm_OverdraftEvent3.事件处理:
private void SecondaryForm_OverdraftEvent(object sender, decimal e)
{
errorMessage.Visible = true;
}
4.并发事件处理:
Both the main form and the secondary form display the overdraft message when the event is triggered.
Tim 强调了清理事件监听器对于防止内存泄漏和确保应用程序正常运行的重要性。
1.取消订阅活动:
customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;RemoveHandler customer.CheckingAccount.OverdraftEvent, AddressOf CheckingAccount_OverdraftEvent为什么这很重要:
2.使用命名方法:
// Good practice: using named methods for event handlers' Good practice: using named methods for event handlersTim Corey 解释了通过事件传递数据的最佳实践,特别是使用类而不是像字符串或十进制数这样的简单数据类型的好处。
Tim 首先讨论了为什么使用简单数据类型来表示事件不太常见,以及为什么通常最好传递一个类:
1.灵活性和可扩展性:
使用类可以通过事件传递多个相关数据。 如果以后需要添加更多数据,只需扩展该类,而无需更改事件的签名。
EventArgs 继承:
Tim 演示了如何为透支事件创建自定义 EventArgs 类。
1.定义类:
public class OverdraftEventArgs : EventArgs
{
public decimal AmountOverdrafted { get; private set; }
public string MoreInfo { get; private set; }
public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo)
{
AmountOverdrafted = amountOverdrafted;
MoreInfo = moreInfo;
}
}
2.在事件中使用类:
public event EventHandler<OverdraftEventArgs> OverdraftEvent;Public Event OverdraftEvent As EventHandler(Of OverdraftEventArgs)3.触发事件:
OverdraftEvent?.Invoke(this, new OverdraftEventArgs(amountNeeded, "Additional info"));OverdraftEvent?.Invoke(Me, New OverdraftEventArgs(amountNeeded, "Additional info"))Tim 强调在 EventArgs 类中使用只读属性的重要性,以防止意外修改事件数据。
1.避免修改:
2.问题示例:
private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
{
e.AmountOverdrafted = 1000; // This modification affects all handlers
}
3.解决方案:
public decimal AmountOverdrafted { get; private set; }
public string MoreInfo { get; private set; }
Tim Corey 指出了使用私有 setter 来设置事件数据属性这一规则的一个重要例外。 当需要允许事件监听器修改事件数据时,例如根据某些条件取消交易时,则属于例外情况。
Tim 举了一个例子,说明事件处理程序可能需要取消交易。 这是通过向自定义 EventArgs 类添加 CancelTransaction 属性来实现的。
1.定义属性:
public class OverdraftEventArgs : EventArgs
{
public decimal AmountOverdrafted { get; private set; }
public string MoreInfo { get; private set; }
public bool CancelTransaction { get; set; } = false;
public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo)
{
AmountOverdrafted = amountOverdrafted;
MoreInfo = moreInfo;
}
}
2.在事件处理程序中设置属性:
private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
{
if (denyOverdraft.Checked)
{
e.CancelTransaction = true;
}
errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}";
errorMessage.Visible = true;
}
3.检查源方法中的属性:
if (args.CancelTransaction)
{
return false; // Transaction is canceled
}
Tim进一步完善了应用程序,使其更具互动性和用户友好性。
1.添加透支控制复选框:
private void InitializeComponent()
{
this.denyOverdraft = new System.Windows.Forms.CheckBox();
// Initialize other controls
this.denyOverdraft.Text = "Stop Overdrafts";
this.denyOverdraft.CheckedChanged += new System.EventHandler(this.denyOverdraft_CheckedChanged);
}
2.处理复选框状态:
private void denyOverdraft_CheckedChanged(object sender, EventArgs e)
{
if (denyOverdraft.Checked)
{
// Logic to stop overdraft transactions
}
}
3.更新事件处理程序:
private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e)
{
if (denyOverdraft.Checked)
{
e.CancelTransaction = true;
}
errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}";
errorMessage.Visible = true;
}
Tim Corey 在教程的最后总结了在 C# 中使用事件的关键点和最佳实践。
1.移除事件监听器:
customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;RemoveHandler customer.CheckingAccount.OverdraftEvent, AddressOf CheckingAccount_OverdraftEvent2.使用EventArgs继承:
3.只读属性的私有设置器:
4.事件处理程序语法:
5.空条件运算符:
Tim Corey 的C# 事件综合教程提供了创建、处理和管理事件的有效方法,并提供了宝贵的见解和实用示例。 遵循这些最佳实践,开发人员可以创建更具交互性和响应性的应用程序。
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy