委托如何使用通用且可扩展的类响应多个事件?

2024-01-08

我已经设计了一种技术来处理 rdlc 报告中的多个子报告,但当我试图使其通用且可重复时,我不得不采用该模型并针对每种情况稍微调整它。

例如,如果我定义一个抽象接口,像这样,我只需根据需要将其从 winform 剪切并粘贴到 winform :

abstract class ISolutionStrategy
{
    public abstract void AlgorithmInterface(Int64 searchCriteria, SubreportProcessingEventArgs e);
}

首先,我希望能够通过包含一个 has-a 对象将其带入每种形式。我还想封装委托处理分派的行为,并使处理方法也成为“通用”。

那么,设计要求是:

  • 创建一个可以包含在winform中的对象来处理多个子报表处理
  • 在winform中实例化并配置对象
  • 在winform中构建调度表或switch/case语句
  • 传入所有方法来处理该 winforms 报表查看器的特定要求

目标是制作一个可以独立测试并坚固耐用的对象,而且不必剪切和粘贴轮子,也不必为每个新的 winform 进行大量手动调整。

在我看来,有人找到了比我目前拥有的更好的设计。

创建一个可以包含在winform中的对象来处理多个子报表处理

到目前为止,我在本地表单加载事件中有一个委托:

this.reportViewer1.LocalReport.SubreportProcessing += new SubreportProcessingEventHandler(LocalReport_SubreportProcessing);

这是由 *LocalReport_SubreportProcessing* 方法中的 switch 语句处理的。

该方法的主体包含一个 switch 语句:

void LocalReport_SubreportProcessing(object sender, SubreportProcessingEventArgs e)

        {
            String commonSubreportKey = _commonSubreportKey;

            switch (e.ReportPath)
            {
                case "rptSubAlternateParts":
                    runSubAlternatePart(e, commonSubreportKey, new GetAlternateParts());
                    break;
                case "rptSubGetAssemblies":
                    runSubFailurePart(e, commonSubreportKey, new GetAssemblies());
                    break;
                case "rptSubGetAssemblies":
                    runSubGetGetEndItemLRMFailureInfo(e, commonSubreportKey, new GetEndItemLRMFailureInfo());
                    break;
                case "rptSubGetAssemblies":
                    runSubGetSubAssemblies(e, commonSubreportKey, new GetSubAssemblies());
                    break;
                default:
                    break;
            }
Aside:

在我看来,与 我考虑过的替代方案。我考虑过在报告中使用哈希 名称作为键,函数调用数据作为值。但是,我 真的不知道该怎么做,我认为这会更难 别人来理解。


之后,调用一个函数,重新排列 switch 语句中从函数调用传递的信息:

    private static void runSubAlternatePart(SubreportProcessingEventArgs e1, String  commonReportKey, GetAlternatePart myAP)
            {
                myAP.AlgorithmInterface(commonReportKey, e1);
            }

这种重新安排肯定是代码口吃,但对于我试图实现的策略模式来说似乎是必要的中间:

     abstract class IStrategy
        {
            public abstract void AlgorithmInterface(String searchParam, SubreportProcessingEventArgs e);

        }

以下是其中一份报告的战略具体实施情况:

class GetAlternatePart : IStrategy
{
private BLL.AlternatePartBLL ds = new BLL.AlternatePartBLL();


public override void AlgorithmInterface(String searchParam, SubreportProcessingEventArgs e)
              {

                    e.DataSources.Clear();
                    DataTable myDataTable = ds.GetAlternativePart(searchParam);
                    DataSet myDataSet = new DataSet();
                    myDataSet.Tables.Add(myDataTable);
                e.DataSources.Add(new ReportDataSource("BLL_AlternatePartBLL", myDataSet.Tables[0]));
            }

        }
    }

无论如何,我的愿望是不必在报告之间重复手动连接相同的逻辑,因为我有许多带有多个子报告的报告。

我想要一种库质量的方式,使用类来动态创建发生口吃的中间部分,并且我想传递一个“匿名”函数,它实际上实现了子报表与其相应数据源的详细连接。

对于带有子报表的单个报表,甚至几个一次性报表,我所做的都是可以的,但是如何才能使其更少的手动、更健壮且更可测试呢?

我的环境是 Visual Studio 2008,目标是 .NET 3.5;抽象类的声明方式和编译方式似乎有所不同。


我建议的解决方案是对基类进行非常简单的重构,它将您需要在每个 WinForm 中编写的代码减少为两件事:1)用于该表单的报表的设置; 2) 定义如何获取该表单的报告数据。

假设每个 WinForm 都继承自一个名为 ReportForm 的基类,则每个 WinForm 的代码将如下所示:

public partial class Form1 : ReportForm
{
    public Form1()
    {
        // Wire up the report used by the Visual Studio-designed report viewer to the base class
        base.WinFormReport = reportViewer1.LocalReport;

        InitializeComponent();
    }

    // The search parameters will be different for every winform, and will presumably
    //  come from some winform UI elements on that form, e.g., parentPartTextBox.Text
    protected override DataResult GetReportData(SubreportProcessingEventArgs e)
    {
        // Return the data result, which contains a data table and a label which will be
        //  passed to the report data source
        // You could use DataSet in DataResult instead of DataTable if needed
        switch (e.ReportPath)
        {
            case "rptSubAlternateParts":
                return new DataResult(
                    new BLL.AlternatePartBLL().GetAlternativePart(parentPartTextBox.Text)
                    , "BLL_AlternatePartBLL"
                );

            case "rptSubGetAssemblies":
                return new DataResult(
                    new BLL.SubAssemblyBLL().GetSubAssemblies(someOtherTextBox.Text)
                    , "BLL_SubAssemblyBLL"
                );

            default:
                throw new NotImplementedException(string.Format("Subreport {0} is not implemented", e.ReportPath));

        }
    }
                                .
                                .
                                .

上面的代码做了这些事情:

1) 告诉基类(ReportForm) Form 中使用了哪个Report。如果您愿意,您也可以将 Report 重构为 ReportForm,但我的方法仍然允许您在 Visual Studio 中创建和操作 ReportViewer 及其报表。但是,如果您以编程方式传递报表而不是在设计器中,则可能需要将报表从派生的 WinForm 类发送到基类中。

2) 定义报表如何获取其所有子报表的数据。为此,我们只需要返回一个数据表和一个标签,因为这就是报表数据源最终需要的全部内容。将 DataTable 和标签绑定到 RDLC 数据源的代码属于基类 (ReportForm),因为该绑定代码对于所有 WinForms 都是通用的。

现在,ReportForm 代码应如下所示:

/// <summary>
/// Don't cut & paste into any Windows Forms, inherit the behavior you want from a base class
/// </summary>
public abstract class ReportForm : System.Windows.Forms.Form
{
    // I'm not sure exactly what this is used for, but I put it in base class in case there is some use for it here
    protected string _commonSubreportKey = "12345";

    // This will be the one line of code needed in each WinForm--providing the base class a reference
    //  to the report, so it has access to the SubreportProcessing event
    protected Report WinFormReport { get; set; }

    // Making this abstract requires each derived WinForm to implement GetReportData--foolproof!
    protected abstract DataResult GetReportData(SubreportProcessingEventArgs e);

    // Wire up the subreport_processing handler when any WinForm loads
    // You could override this in derived WinForms classes if you need different behavior for some WinForms,
    //  but I would bet this default behavior will serve well in most or all cases
    protected virtual void Form1_Load(object sender, EventArgs e)
    {
        Report.SubreportProcessing += new SubreportProcessingEventHandler(LocalReport_SubreportProcessing);
    }

    // When the Subreport processing event fires, handle it here
    // You could also override this method in a derived class if need be
    protected virtual void LocalReport_SubreportProcessing(object sender, SubreportProcessingEventArgs e)
    {
        // Get the data needed for the subreport
        DataResult dataResult = this.GetReportData(e);

        e.DataSources.Clear();
        e.DataSources.Add(new ReportDataSource(dataResult.Label, dataResult.Table));
    }
}

请注意,ReportForm 基类继承自 Form,然后所有 WinForm 都将继承自 ReportForm——这是整个设计的关键。下面是这个 ReportForm 基类的工作原理:

1)当实例化WinForm时,设置了基本属性WinFormReport,因此基本对象知道正在使用哪个Report。

2)当WinForm加载时,Form Load事件在基类上被调用,因为它没有在派生类中定义。加载表单时,将连接报表的 Subreport_Processing 事件。

3) 当用户输入参数并单击某些内容以在报表查看器中创建报表时,最终子报表将由 RDLC 实例化,并且 Subreport_Processing 事件会多次触发,每个子报表触发一次。

4) 当事件触发时,基类事件处理程序调用 GetReportData(e),这将调用 WinForm 上定义的 GetReportData 方法。注意,该方法在基类中是抽象的,因此不能在基类上定义,而必须在派生类中定义。

5) WinForm 中的 GetReportData(e) 方法使用您最初指定的调度程序逻辑,将 DataTable(如果需要,也可以是 DataSet)和文本字符串返回到基本处理程序。

6) 基本处理程序获取 DataTable/DataSet 和文本字符串,将它们作为报告数据源提供给报告,并且还可以执行显示报告所需的任何其他操作。

经过深思熟虑,我决定建议将常见行为相当简单地重构为基类,因为我认为它可以满足您的要求,并且我没有看到哪里需要更复杂的东西。我认为您会发现这种方法非常可读,它绝对最小化了每个新 WinForm 中所需的内容,最重要的是,发现它具有极强的可扩展性;也就是说,当您继续开发系统时,您总是会问“这个新代码是否需要在每个 WinForm 中重复,或者是否很常见,因此应该进入基类?”

如果您对此方法有任何疑问或疑虑,请随时添加评论,祝您好运。我希望这正是您正在寻找的!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

委托如何使用通用且可扩展的类响应多个事件? 的相关文章

  • 将类对象放置在向量中?

    我注意到我可以将一个类放置在一个向量中 这是我的程序 我收到以下错误 out blackjack exe blackjack obj blackjack obj error LNK2019 unresolved external symbo
  • 如何在类文件中使用 Url.Action() ?

    如何在 MVC 项目的类文件中使用 Url Action Like namespace 3harf public class myFunction public static void CheckUserAdminPanelPermissi
  • 现代 C++ 编译器是否能够在某些情况下避免调用 const 函数两次?

    例如 如果我有以下代码 class SomeDataProcessor public bool calc const SomeData d1 const SomeData d2 const private Some non mutable
  • 未找到 Boost 库,但编译正常

    我正在尝试在 C 中使用 boost 的文件系统 使用时看起来编译没问题 c c Analyse c o Analyse o g W Wall L usr local lib lboost filesystem lboost system
  • 语音识别编程问题入门

    所以 你们可能都看过 钢铁侠 其中托尼与一个名为贾维斯的人工智能系统进行交互 演示剪辑here http www youtube com watch v Go8zsh1Ev6Y 抱歉 这是广告 我非常熟悉 C C 和 Visual Basi
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • 如何使用 ASP.NET Core 获取其他用户的声明

    我仍在学习 ASP NET Core 的身份 我正在进行基于声明的令牌授权 大多数示例都是关于 当前 登录用户的 就我而言 我的 RPC 服务正在接收身份数据库中某个用户的用户名和密码 我需要 验证是否存在具有此类凭据的用户 获取该用户的所
  • 在 VS 中运行时如何查看 C# 控制台程序的输出?

    我刚刚编写了一个名为 helloworld 的聪明程序 它是一个 C NET 4 5 控制台应用程序 在扭曲的嵌套逻辑迷宫深处 使用了 Console WriteLine 当我在命令行运行它时 它会运行并且我会看到输出 我可以执行其他命令并
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • 不可变类与结构

    以下是类与 C 中的结构的唯一区别 如果我错了 请纠正我 类变量是引用 而结构变量是值 因此在赋值和参数传递中复制结构的整个值 类变量是存储在堆栈上的指针 指向堆上的内存 而结构变量作为值存储在堆上 假设我有一个不可变的结构 该结构的字段一
  • 在 C 中使用枚举而不是 #defines 作为编译时常量是否合理?

    在 C 工作了一段时间后 我将回到 C 开发领域 我已经意识到 在不必要的时候应该避免使用宏 以便让编译器在编译时为您做更多的工作 因此 对于常量值 在 C 中我将使用静态 const 变量或 C 11 枚举类来实现良好的作用域 在 C 中
  • 如何最好地以编程方式将 `__attribute__ ((unused))` 应用于这些自动生成的对象?

    In my makefile我有以下目标 它将文本 HTML 资源 编译 为unsigned char数组使用xxd i http linuxcommand org man pages xxd1 html 我将结果包装在匿名命名空间和标头保
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • Visual Studio 2015:v120 与 v140?

    仅供参考 Win10 x64 我今天开始尝试 Visual Studio 2015 在弄清楚如何运行 C C 部分后 我尝试加载一个大型个人项目 该项目使用非官方的glsdk http glsdk sourceforge net docs
  • 如何解压 msgpack 文件?

    我正在将 msgpack 编码的数据写入文件 在编写时 我只是使用 C API 的 fbuffer 如 我为示例删除了所有错误处理 FILE fp fopen filename ab msgpack packer pk msgpack pa
  • 了解 Lambda 表达式和委托 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经尝试解决这个问题很长一段时间了 阅读在线博客和文章 但到目前为止还没有成功 什么是代表 什么是 Lambda 表达式 两者的优点
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person
  • 没有“对 *this”功能的右值引用的解决方法

    我有一个围绕可移动对象的代理容器类 并希望代理能够隐式生成对底层对象的右值引用 但仅当代理本身被移动时 我相信我将能够按照提案 n2439 实施此行为 将移动语义扩展到 this http www open std org jtc1 sc2
  • 当用户更改 Windows 中的语言键盘布局时如何通知?

    I want to show a message to user when the user changes the language keyboard layout of Windows for example from EN to FR

随机推荐

  • Jquery .on 与双击事件

    为什么这会起作用 document on dblclick areaA tr has td function e code here 这并不 areaA tr has td on dblclick function e Code here
  • 为什么匿名类中只能访问最终变量?

    a只能在这里最终决定 为什么 我怎样才能重新分配a in onClick 方法而不将其保留为私有成员 private void f Button b final int a b addClickHandler new ClickHandle
  • 为什么缺少 object.__getattr__ ?

    为什么object似乎没有 getattr 方法 它定义了两者 setattr and delattr 这三个都不需要吗 gt gt gt object setattr
  • CNContact 标识符中的“:ABPerson”字符串是什么?

    我的 iOS 应用程序会时不时地检查联系人并将新联系人导入到自己的数据库中 我检查了该联系人 它已经存在identifier字段 通常由 UUID 填充 CNContactStore store CNContactStore new sto
  • 关闭 Tkinter 后运行 wxPython

    我们有两个应用程序 一个使用 Tkinter 界面开发 另一个使用 wxPython 构建 两者都相当复杂 运行完 Tkinter 应用程序后 我希望在选择 Tkinter 应用程序中的按钮后运行 wxPython 应用程序 是否可以切换事
  • 在 PHP 中将段落分解为句子

    我一直在使用 explode mystring 将段落拆分成句子 然而 这不包括用不同标点符号结束的句子 例如 有没有办法使用数组而不是单个字符作为分隔符 或者还有另一种使用各种标点符号进行拆分的巧妙方法吗 I tried explode
  • 使用阻塞 IO 的多线程会损坏 Java 中的文件

    AIM 使用 Java 中的阻塞 IO 构建多线程应用程序来下载文件 请不要建议我使用非阻塞 IO 我被告知要使用这个 Issue 我的代码在下载服务器上托管的文件的客户端计算机上运行良好 但是 问题是我的服务器使用多个线程播种文件 在所有
  • ViewBag、ViewData、TempData、Session - 如何以及何时使用它们?

    ViewData 和 ViewBag 允许您访问视图中从控制器传递的任何数据 这两者之间的主要区别在于访问数据的方式 在 ViewBag 中 您使用字符串作为键来访问数据 ViewBag numbers 在 ViewData 中 您使用属性
  • 服务和广播接收器之间的区别

    我试图了解服务和广播接收器之间的区别是什么 在我看来 他们也可以做同样的事情 例如我有一个应用程序 App1 提供名为 ToastHelloWorld 的服务 该服务仅创建一个 Toast 和 stopSelf 我使用带有操作名称的意图过滤
  • 适用于 Android 的 card.io Mono (Xamarin Studio)

    有没有人成功创建了一个他们愿意分享的card io包装器 可以在Android应用程序的Mono中使用 或者有人可以阐明我做错了什么吗 创建一个新的Android Java 绑定库 Project 添加 jar 和 so 文件卡 io SD
  • 找出 Google Big Query 中每个字段占用的空间量

    我想优化我的 Big Query 和 google 存储表的空间 有没有办法轻松找出表中每个字段所获得的累积空间 这对我来说并不简单 因为我有一个复杂的层次结构 有许多重复的记录 您可以在 Web UI 中执行此操作 只需在下面的查询中键入
  • 增强位于 TypeScript 中声明的命名空间中的接口

    我想增强IHttpPromise
  • 在 Matlab 中使用 Java 类

    我已经为这个问题苦苦挣扎了两天 但我发现没有任何资源能够解决它 我试图从Matlab 版本7 13 0 564 R2011b 调用java类 在底部添加了链接 我已经使用 java 1 6 将 java 类编译成 class 文件 并且还使
  • 使用 bfg repo clean 从多个分支中删除多个文件

    我想使用 bfg repo clean 从多个分支中删除多个文件 任何人都可以建议如何做到这一点 我可以使用命令从单个分支中删除单个文件bfg delete files filename my repo git 请提供如何做到这一点的步骤
  • Flutter 未检测到 Android Studio

    我已经在我的 Ubuntu 机器上正确安装了 flutter 我还安装了 Android Studio 及其插件 Flutter 和 Dart 无论如何 当我跑步时 flutter doctor verbose 我得到这个输出 Flutte
  • Swift/iOS8:为什么页面控制指示器不显示?

    我正在实现一个简单的图库视图控制器 其中应用程序显示用户可以滚动浏览的一小部分全屏图像 我正在使用 UIPageViewController 我认为如果我实现了正确的数据源功能 应该自动显示页面控制指示器 但是我仍然看不到任何指标 在我的主
  • 如何在全景/光球模式下直接打开相机?

    我在 Android 4 2 Jelly Bean 中遇到了一个问题 如何从我的应用程序中打开相机 默认情况下处于全景 360 度光球模式 我已经搜索了很多grepcode http grepcode com file repository
  • 类型 Map 不适用

    我有以下内容JAVA由于接口而实现的方法 public String importDocument ImportSource source Map
  • Visual Studio 在加载时意外添加功能

    我在 Visual Studio 2013 中有一个 SharePoint 2010 解决方案 每次我关闭并重新打开 Visual Studio 时 都会向该解决方案添加一项新功能 其中包含一个列表 该列表已从它应该位于的另一个功能中删除
  • 委托如何使用通用且可扩展的类响应多个事件?

    我已经设计了一种技术来处理 rdlc 报告中的多个子报告 但当我试图使其通用且可重复时 我不得不采用该模型并针对每种情况稍微调整它 例如 如果我定义一个抽象接口 像这样 我只需根据需要将其从 winform 剪切并粘贴到 winform a