1

Here is the base class:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Reporting.WinForms;

abstract class ReportWinForm : System.Windows.Forms.Form
{
    // 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 ReportViewer WinFormReportViewer { 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)
    {
        WinFormReportViewer.LocalReport.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));
    }
}

Here is the concrete implementation:

public frmTestAllView()
{
    //base.WinFormReportViewer = reportViewer1; //Hook-up callbacks to the base class      ReportWinForm
    InitializeComponent();
}

private void frmTestAllView_Load(object sender, EventArgs e)
{
    // TODO: This line of code loads data into the 'AFC_ObsolescenceDataSet.up_Fill_frmInternalCaseStatus_All' table. You can move, or remove it, as needed.
    this.up_Fill_frmInternalCaseStatus_AllTableAdapter.Fill(this.AFC_ObsolescenceDataSet.up_Fill_frmInternalCaseStatus_All);

    this.reportViewer1.RefreshReport();
}

// 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));

    }
}

There are two problems:

  1. DataResult is unrecognized by Visual Studio 2008, even though it is in the ReportWinForm base class.
  2. The designer in VS 2008 claims that a class derived from ReportWinForm cannot be edited, even though the base class is descends from Form.

For more context, please see How can a delegate respond to multiple events with a generic and extensible class?

Community
  • 1
  • 1
bentaisan
  • 1,056
  • 3
  • 12
  • 29
  • 1
    I don't see where you define a `DataResult` class "in the ReportWinForm base class". You'll have to provide more detail about what the designer is telling you, there's all sorts of reasons why it can't edit a `Form`-based class. – Peter Ritchie Feb 14 '13 at 18:27
  • Also, there's many usages of "DataResult", please detail which uses VS is having a problem with and the exact error message(s). – Peter Ritchie Feb 14 '13 at 18:28
  • Also, in what way are you having a problem with "Delegate" as described in your title? – Peter Ritchie Feb 14 '13 at 18:29
  • 1
    I know the WPF designer does not allow you to design a class whose base class cannot be constructed with a default constructor (i.e. abstract classes cannot be constructed at all, so fail). I suspect WinForms has the same problem. – Dana Cartwright Feb 14 '13 at 18:29
  • I think Dana has this right. The base class does not have to be marked as abstract, you could just remove the abstract keyword from both base class and GetReportData method therein, and see if it works. – J.T. Taylor Feb 14 '13 at 18:35
  • Ok, the designer accept the class after I remove the abstract keyword. – bentaisan Feb 14 '13 at 19:17
  • I removed DataResult and just used DataTable to hold the results. I only have one scalar returned for all the subreports, so this should keep me going. – bentaisan Feb 14 '13 at 19:21
  • I seems that my answer didn't solve your problems in any way. You could ask @DanaCartwright to turn his comment into an answer and accept that instead. – Daniel A.A. Pelsmaeker Feb 14 '13 at 21:15

1 Answers1

1

DataResult is unrecognized by Visual Studio 2008, even though it is in the ReportWinForm base class.

If it is really in the class, outside of the class you should specify ReportWinForm.DataResult.

The designer in VS 2008 claims that a class derived from ReportWinForm cannot be edited, even though the base class is descends from Form.

Are you sure you have all DLL dependencies correct? You need all DLLs in which all base classes are defined.

By the way, you can download Visual Studio 2012 Express edition for free, if you can and want to upgrade.

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157