首页 > 编程语言 >【C#】【winforms】MVP架构中从 Model 或 View 层主动向 Presenter 传递数据或调用处理逻辑的良好设计——事件触发

【C#】【winforms】MVP架构中从 Model 或 View 层主动向 Presenter 传递数据或调用处理逻辑的良好设计——事件触发

时间:2024-11-21 14:29:36浏览次数:1  
标签:MVP 触发 EventHandler C# Presenter 事件 传递数据 Model DataReceived

背景

使用winforms做上位机软件,软件功能简单来说就是与串口通信。

因为一个软件要应用于不同型号的下位机,采用MVP架构提高代码复用性。

 

其中Model层中实例化SerialPort 对象:

private SerialPort _serialPort;

只关注串口收发。

 

presenter层负责主要业务逻辑。

view层负责界面更新。这次讨论不涉及到,暂且不谈。

 

从 Model 或 View 层主动向 Presenter 传递数据或调用处理逻辑

当model层收到数据后,根据单一职责原则(SRP),后续处理需要在presenter层中实现。

这就有了标题写的“从 Model 或 View 层主动向 Presenter 传递数据或调用处理逻辑”这个需求。

 

这时候,我的第一思维可能是在presenter中写个处理方法然后在model中调用。

但是,通常情况下,Presenter 会实例化 Model 和 View,并持有它们的引用。

Model 和 View 并不知道 Presenter 的存在,也不应该直接调用 Presenter 的方法。

因此,从客观上讲,Model 无法直接调用 Presenter 中的处理逻辑。

 

这样的话就只能传递数据过去,然后提醒那边接收。这就完全符合事件机制(事件驱动编程)的使用场景。

 

**在 Model 中定义事件:**Model 定义一个或多个事件,用于在数据发生变化或接收到新数据时通知订阅者。

public class MVP_SerialPortModel
{
    // 定义数据接收事件
    public event EventHandler<DataEventArgs> DataReceived;

    // 触发事件的方法
    private void OnSerialDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        byte[] data = ReadDataFromSerialPort();
        DataReceived?.Invoke(this, new DataEventArgs(data));
    }
}

 

**在 Presenter 中订阅事件:**Presenter 实例化 Model,并订阅其事件。当事件被触发时,Presenter 的事件处理方法被调用,可以继续处理业务逻辑。

public class Presenter
{
    private MVP_SerialPortModel model;

    public Presenter()
    {
        model = new MVP_SerialPortModel();
        model.DataReceived += OnDataReceived;
    }

    private void OnDataReceived(object sender, DataEventArgs e)
    {
        byte[] data = e.Data;
        // 处理数据的业务逻辑
    }
}

 

触发顺序如下:

  1. 数据到达串口:

    • 串口接收到数据。
  2. SerialPort 触发 DataReceived 事件:

    • SerialPort 类触发其内置的 DataReceived 事件。
    • 由于 SerialPortManager 已经订阅了该事件: serialPort.DataReceived += OnSerialDataReceived;
    • 因此,OnSerialDataReceived 方法被调用。
  3. OnSerialDataReceived 方法执行:

    • 在该方法中,从串口读取数据(字节数组)。
    • 读取数据后,SerialPortManager 触发其自定义的 DataReceived 事件,将数据传递给订阅者: DataReceived?.Invoke(this, new DataEventArgs(buffer));
  4. SerialPortManagerDataReceived 事件触发:

    • 由于 SomeClass 已经订阅了 SerialPortManagerDataReceived 事件: portManager.DataReceived += OnDataReceived;
    • 因此,OnDataReceived 方法被调用。
  5. OnDataReceived 方法执行:

    • 接收并处理传递过来的数据。
    • 如果需要更新 UI,使用 Invoke 确保在主线程上执行。

 

为什么在 Model 中定义事件,由 Presenter 订阅是正确的做法

  • **解耦合:**通过事件机制,Model 不需要知道谁会订阅事件,也不需要依赖于具体的 Presenter。这样可以保持 Model 的独立性和可重用性。

  • **职责分离:**Model 专注于数据的收发和存储,业务逻辑和处理则由 Presenter 负责。这符合单一职责原则(SRP)。

  • **遵循 MVP 模式:**在 MVP 模式中,Presenter 充当中介者,负责处理业务逻辑和更新 View。Model 和 View 不直接通信,也不应该依赖于 Presenter。

  • **避免循环依赖:**如果 Model 直接调用 Presenter 的方法,会导致循环依赖,破坏层次化设计,增加代码的复杂性和维护成本。

 

相关的设计模式和概念

  • **观察者模式(Observer Pattern):**这是一种行为型设计模式,定义了对象间的一对多依赖。当一个对象的状态发生变化时,所有依赖于它的对象都会自动收到通知并更新。这正是事件机制背后的原理。

  • **事件驱动编程:**程序的流程是由事件的发生来驱动的。在 .NET 中,事件和委托提供了对事件驱动编程的良好支持。

  • **依赖倒置原则(Dependency Inversion Principle,DIP):**高层模块不应该依赖于低层模块,二者都应该依赖于抽象。通过事件和接口,可以实现依赖倒置,降低模块间的耦合。

 

事件的参数类

 这个事件上文中的事件:

public event EventHandler<DataEventArgs> DataReceived;

中涉及到的参数类也需要定义一下:

//更新后的 DataEventArgs 类,用于封装字节数据
public class DataEventArgs : EventArgs
{
    public byte[] Data { get; }

    public DataEventArgs(byte[] data)
    {
        Data = data;
    }
}

 

 

1. 关于 EventArgs

EventArgs 是 .NET 中用于传递事件数据的基类。它是一个空的类,表示事件不包含任何数据。如果你需要在事件中传递数据,可以创建一个从 EventArgs 派生的自定义类,包含你需要的属性。

示例:

  • **没有数据的事件:**使用 EventArgs.Empty,表示事件不包含任何数据。
  • **包含数据的事件:**创建一个继承自 EventArgs 的类,添加需要的属性。

 

2. 事件的定义与 EventHandler<TEventArgs>

在 .NET 中,事件通常使用委托类型 EventHandlerEventHandler<TEventArgs> 定义:

  • **EventHandler:**用于不需要传递数据的事件。它的签名是 void EventHandler(object sender, EventArgs e)(调用时e就给EventArgs.Empty)
  • **EventHandler<TEventArgs>:**用于需要传递数据的事件。TEventArgs 是继承自 EventArgs 的类型。

上文代码中事件的定义:

public event EventHandler<DataEventArgs> DataReceived;
  • **EventHandler<DataEventArgs>:**表示事件处理方法需要接受一个 DataEventArgs 类型的参数。

 

3. 事件与参数的关系

  • 在 C# 中,定义事件时必须指定事件处理器(事件处理方法)的委托类型,这个委托类型规定了事件触发时的参数格式,以及订阅该事件的处理器方法的签名。
  • **事件触发时传递参数:**当需要主动用代码触发(调用)事件时,需要提供两个参数:sendere。**sender:**通常是触发事件的对象(this)。**e:**事件数据,类型为 EventArgs 或其子类。
  • **订阅者访问参数:**所有订阅了该事件的方法(事件处理程序)都会在事件触发时被调用,并接收到触发时传递的参数。

 

标签:MVP,触发,EventHandler,C#,Presenter,事件,传递数据,Model,DataReceived
From: https://www.cnblogs.com/ban-boi-making-dinner/p/18560330

相关文章

  • 构建医学文献智能助手:基于 LangChain 的专业领域 RAG 系统实践
    前言在当今医疗科技快速发展的时代,每天都有数以千计的医学研究成果在全球范围内发表。从临床试验报告到基础研究论文,从流行病学调查到药物研发数据,这些专业文献承载着推动医学进步的重要知识。然而,面对如此海量且专业性极强的文献资料,医疗从业者往往感到力不从心。如何在有限的时......
  • java.lang.IllegalArgumentException: Unsupported class file major version xx解决
    在一次项目打包中遇到了这个问题,这个问题的本质是打包时,你依赖的包或这些依赖的间接依赖中含有高于当前项目构建jdk版本编译出来的类,导致打包失败。1.majorversion和jdk各版本对应关系可以自行搜索,当前主要版本的对应关系是c:55对应java11majorversion:52对应java8maj......
  • CentOS 7远程连接相关问题
    1、检查网络配置正确。ipaddrshowroute-n2、检查防火墙状态(关闭防火墙)。检查防火墙状态:systemctlstatusfirewalld如果防火墙处于活动状态,允许SSH连接:firewall-cmd--permanent--add-service=ssh重新加载防火墙配置:firewall-cmd--reload3、检查SSH检查SSH服务状态:sy......
  • Deep Residual Learning for Image Recognition 翻译
    Doc2X|PDF到Markdown一步搞定只需几秒,Doc2X即可将PDF转换为Markdown,支持批量处理和深度翻译功能。Doc2X|One-StepPDFtoMarkdownConversionInjustseconds,Doc2XconvertsPDFstoMarkdown,withsupportforbatchprocessingandadvancedtranslatio......
  • 前端开发调试之 PC 端调试学习笔记
    一、引言在前端开发过程中,调试是至关重要的一个环节。它能帮助我们快速定位代码中的问题,无论是页面布局错乱、交互效果异常还是性能不佳等情况,通过有效的调试手段都可以找到根源并进行修复。而在PC端进行调试有着其特定的方法和技巧,以下就是关于前端开发中PC端调试的详细......
  • Codeforces ICPC那场
    在许多题目中,我原来感觉第二题应该是不难的,结果难的我都不想做了,所以发一下第二题的题解。题目的意思便是对一个列表,任意选择范围内的索引i,使A[i]-=2,A[(i+1)%len(A)]+=1,我的第一想法便是用差分,使差分列表全部为零即可,但是操作就变得无规律了为什么我会想到用差分呢,因为改......
  • AbMole|Reboxetine mesylate 瑞波西汀甲磺酸盐;甲磺酸瑞波西汀盐(CAS号98769-84-7;目录号
    Reboxetinemesylate(瑞波西汀甲磺酸盐,甲磺酸瑞波西汀盐)是一种选择性的去甲肾上腺再摄取抑制剂(NRIs),Ki值为8.2nM。可用于抑郁的相关研究。生物活性Reboxetinemesylate(瑞波西汀甲磺酸盐,甲磺酸瑞波西汀盐)是一种有效的,选择性的去甲肾上腺再摄取抑制剂(NRIs),Ki值为8.2nM。可用于......
  • 红帽RHCE和RHCA是什么关系?三分钟读懂!
    在Linux系统管理方面,红帽认证专家(RHCE)和红帽认证架构师(RHCA)是两个响当当的认证。它们都由红帽公司(RedHat)颁发,旨在证明持有者在Linux系统管理、部署和架构方面的专业技能。那么,RHCE和RHCA之间究竟是什么关系呢?RHCE和RHCA是什么关系?首先,让我们了解一下这两个认证的......
  • 国内ChatGPT中文版镜像网站攻略整理(11月21日最新更新)
    ChatGPT中文版镜像站专为中文用户优化,提供本地化的界面和功能,提升用户体验。通过ChatGPT中文版镜像站,用户不仅可以享受更快的访问速度,还能绕过地区限制,确保顺畅的使用体验。此外,这些镜像站结合丰富的定制功能,进一步满足中文用户的多样化需求。一、GPT中文镜像站① www.yixia......
  • 尝试:增加Chrome进程稳定性的参数
    https://www.bilibili.com/opus/832573985795342345 增加Chrome进程的稳定性的确切参数可能因Chrome版本和操作系统而异。然而,以下是一些常见的命令行参数,可以在启动Chrome时尝试以提高稳定性:--disable-extensions: 这将禁用所有插件和扩展,有时插件可能会引起稳定性问题。-......