Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can a delegate respond to multiple events with a generic and extensible class?
    primarykey
    data
    text
    <p>I have rigged up a technique to handle multiple subreports in an rdlc report, but as I have tried to make it generic and repeatable, I have instead had to take the model and tweak it slightly for each case.</p> <p>For example, if I define an abstract interface, like such, I just cut and paste it from winform to winform as needed:</p> <pre><code>abstract class ISolutionStrategy { public abstract void AlgorithmInterface(Int64 searchCriteria, SubreportProcessingEventArgs e); } </code></pre> <hr> <p>First, I want to be able to bring this into each form by including an has-a object. I also want to encapsulate the behaviors of handling the dispatching by the delegate, and make the handling methods "generic" as well.</p> <p>So, the design requirements are:</p> <ul> <li>Create an object that can be included in a winform to handle multiple subreport processing</li> <li>Instantiate and configure the object in the winform</li> <li>Build the dispatch table or switch/case statement in the winform</li> <li>Pass in all the methods to handle the specific requirments of that winform's report viewer</li> </ul> <p>The GOAL is to make an object that can be tested standalone and made robust, and also to not have to cut and paste the wheel and do a bunch of manual tweaking for each new winform.</p> <p>It seems to me that someone has found a better design out there than the one I currently have.</p> <p>Create an object that can be included in a winform to handle multiple subreport processing</p> <p>So far, I have a delegate in the local forms load event:</p> <pre><code>this.reportViewer1.LocalReport.SubreportProcessing += new SubreportProcessingEventHandler(LocalReport_SubreportProcessing); </code></pre> <p>which is handled by a switch statement in the *LocalReport_SubreportProcessing* method.</p> <p>The body of the method contains a switch statement:</p> <pre><code>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; } </code></pre> <blockquote> Aside: <p><em>In my opinion, the switch is mostly human readable compared to the alternative I considered. I considered using a hash with the report name as the key and the function call data as the value. However, I did not really know how to do it and I thought it would be harder for someone else to understand.</em></p> </blockquote> <hr> <p>After that, a call is made to a function that rearranges the information passed from the function call in the switch statement:</p> <pre><code> private static void runSubAlternatePart(SubreportProcessingEventArgs e1, String commonReportKey, GetAlternatePart myAP) { myAP.AlgorithmInterface(commonReportKey, e1); } </code></pre> <p>This rearrangement is definitely code stuttering, but is a seemingly necessary intermediate to the Strategy pattern I am attempting to implement:</p> <pre><code> abstract class IStrategy { public abstract void AlgorithmInterface(String searchParam, SubreportProcessingEventArgs e); } </code></pre> <p>Here is a concrete implementation of the Strategy for one of the reports:</p> <pre><code>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])); } } } </code></pre> <p>In any case, my desire is to not have to hand wire the same logic repeatedly between reports, as I have many reports with multiple subreports.</p> <p>I would like a library quality way of using a class to dynamically create the middle parts where the stuttering occurs, and I would like to pass in an "anonymous" funciton which actually implements the detailed connecting of the subreport to its corresponding data source.</p> <p>For a single report with subreports, or even a few one-off reports, what I am doing is ok, but how can it be made less manual, more robust and more testable?</p> <p>My environment is Visual Studio 2008 with a target of .NET 3.5; there seems to be a difference in how abstract classes are declared and how they are compiled.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. COTo absolutely minimize cut and paste, and to stay as DRY as possible, I would recommend a design goal of having less code in each Winform than you have specified. For example, do you need a dispatch table in each WinForm, or could you just name your methods to match e.ReportPath, and then invoke via Reflection? Also, your switch code is illegal--you have 3 case "rptSubGetAssemblies", which makes it a little more difficult to understand exactly what you are trying to do. Could you edit to correct the code?
      singulars
    2. COAnother thought I have is that the need for human readability pales in comparison to making the code DRY. If you need to use nested generics and expression trees here to simplify implementation within each winform, then that is the right thing to do.
      singulars
    3. COFinally, when you write "Pass in all the methods to handle the specific requirements of that winform's report viewer", how different are these methods from one another? Do they all derive from the same base class? Do they have similar method signatures such that they can be represented by a common delegate? I ask this b/c I'm not sold on the need for Strategy pattern here, instead suspecting this could be implemented more simply with either generics and reflection (if your GetXxx methods are very similar to one another), or expression trees (in the more complex case that they are not).
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload