none
ReportViewer Click Event is not firing RRS feed

  • Question

  • In VS 2008 I have a Windows Forms control that needs custom report navigation handling. 

    The control is a panel with a tab control. The first tab is called Overview and is a dashboard of multiple small remote Reporting Services graphs. To do this it has a splitter panel with several reportViewer controls.  When a user clicks on a graph, a new tab should be generated with a corresponding detailed Reporting Services remote report. 

    So far, I can get this to work only for the Graph Title or Data Series by:
    1) adding a drillthrough to the title or data series (through the Action tab in their Properties box).
    2) adding a handler to the reportViewer Drillthrough action that immediately cancels the drillthrough & then calls a custom Load method to create the new tab & reportViewer.

    Ideally, this should happen whenever the user clicks anywhere on the graph, so I added an event handler to the reportViewer Click event but it does not get called.  I also tried the DoubleClick & MouseClick & MouseDoubleClick & MouseUp events, but none of those fire when I click on the graph.

    Why is the reportViewer ignoring user interaction?

    Is there a way to cause custom navigation when the user clicks anywhere on the graph or report?
    Scott D Duncan
    Friday, March 13, 2009 4:22 PM

Answers

  • I have long been less than thrilled with the ReportViewer control. I ran into a similar problem as you and dug in with Reflector.NET and found that the main problem is that the ReportViewer control is a massive tangle of other panels/controls and that several of the main ones that actually do display work have MouseClick handlers and no logic to bubble up to the parent control.

    I'm using the 2010 ReportViewer which I believe is slightly different internally than the 2008 one, this matters because the kludge/solution I came up with is based on using reflection to get access to the guts to add our click handlers.

    private void ApplyActionToInternalReportViewerControls(Action<Control> action)
    {
      try
      {
       // Lets just dig in, not even bothering with any null checks or other preventive coding. If things go bad just bail to exception handler
       var reportViewerType = typeof (Microsoft.Reporting.WinForms.ReportViewer);
       var winRSviewerField = reportViewerType.GetField("winRSviewer", BindingFlags.Instance | BindingFlags.NonPublic);
       var reportPanelField = winRSviewerField.FieldType.GetField("m_reportPanel", BindingFlags.Instance | BindingFlags.NonPublic);
       var renderPanelField = reportPanelField.FieldType.GetField("m_renderPanel", BindingFlags.Instance | BindingFlags.NonPublic);
    
       var winRSviewer = winRSviewerField.GetValue(this.reportViewer) as Control;
       var reportPanel = reportPanelField.GetValue(winRSviewer) as Control;
       var renderPanel = renderPanelField.GetValue(reportPanel) as Control;
    
       action(winRSviewer);
       action(reportPanel);
       action(renderPanel);
      }
      catch (Exception ex)
      {
       // Log or ignore
      }
     }
    

    Then in the constructor:

     this.ApplyActionToInternalReportViewerControls(c => c.Click += this.DoSomeClickHandlingStuff);

     

    Ugly, horrible kludge, but it seems to work, there could be corner cases where other controls that I haven't tracked down are displayed in the main ReportViewer window.

    • Marked as answer by ScottDuncan Thursday, December 30, 2010 4:02 PM
    Thursday, October 28, 2010 7:18 AM

All replies

  • I have long been less than thrilled with the ReportViewer control. I ran into a similar problem as you and dug in with Reflector.NET and found that the main problem is that the ReportViewer control is a massive tangle of other panels/controls and that several of the main ones that actually do display work have MouseClick handlers and no logic to bubble up to the parent control.

    I'm using the 2010 ReportViewer which I believe is slightly different internally than the 2008 one, this matters because the kludge/solution I came up with is based on using reflection to get access to the guts to add our click handlers.

    private void ApplyActionToInternalReportViewerControls(Action<Control> action)
    {
      try
      {
       // Lets just dig in, not even bothering with any null checks or other preventive coding. If things go bad just bail to exception handler
       var reportViewerType = typeof (Microsoft.Reporting.WinForms.ReportViewer);
       var winRSviewerField = reportViewerType.GetField("winRSviewer", BindingFlags.Instance | BindingFlags.NonPublic);
       var reportPanelField = winRSviewerField.FieldType.GetField("m_reportPanel", BindingFlags.Instance | BindingFlags.NonPublic);
       var renderPanelField = reportPanelField.FieldType.GetField("m_renderPanel", BindingFlags.Instance | BindingFlags.NonPublic);
    
       var winRSviewer = winRSviewerField.GetValue(this.reportViewer) as Control;
       var reportPanel = reportPanelField.GetValue(winRSviewer) as Control;
       var renderPanel = renderPanelField.GetValue(reportPanel) as Control;
    
       action(winRSviewer);
       action(reportPanel);
       action(renderPanel);
      }
      catch (Exception ex)
      {
       // Log or ignore
      }
     }
    

    Then in the constructor:

     this.ApplyActionToInternalReportViewerControls(c => c.Click += this.DoSomeClickHandlingStuff);

     

    Ugly, horrible kludge, but it seems to work, there could be corner cases where other controls that I haven't tracked down are displayed in the main ReportViewer window.

    • Marked as answer by ScottDuncan Thursday, December 30, 2010 4:02 PM
    Thursday, October 28, 2010 7:18 AM
  • I strongly recommend against using reflection on the internal structures of the ReportViewer control.  This is definitely not supported and stands a good chance of breaking with future releases or even service packs.

    The viewer does not make use of the Click event, partly because that event does not allow us to surface enough information for it to be useful when you click somewhere in the report.  Instead, a number of other events are exposed for the various ways you can interact with a report, such as the Toggle event, Drillthrough event, and Hyperlink event.  There are also events for toolbar based functionality such as the ZoomChange event.

    Friday, October 29, 2010 3:10 AM
    Moderator
  • I think I noted strongly enough in my kludge that it is a bad idea and that it is specific to the 2010 viewer. But it also works.

    It does have a built in assumption (true in my case) that you have control over which ReportViewer version is shipped with your product. If that is not the case it could very well break in upgrade scenarios. Wouldn't be too hard to check versioning and have different reflection code paths for future versions as they are released.

    Or.... the ReportViewer team could add a working Click handler to the ReportViewer object.

    All of the events you list are specific to requesting action from the Report Viewer, none of which actually do anything to solve the question at hand. We just need a event saying something/anything/don't care what really inside the report viewer was clicked. So when you say you couldn't surface enough information to be useful you're missing the fact that the event being fired with no additional information could and is in this case useful and desirable.

    In my case (which sounds similar to Scott's) I have a dashboard like page with a grid or ReportViewer controls (no toolbars on them, just the report panel). I want the user to be able to click any of the ReportViewer elements to indicate that they are selecting that element. Even when the report hasn't run yet, has an error, or regardless of what content is loaded into it. Its not about interacting with the report, its about selection. ReportViewer.Click is exactly what I want.

    I'm open to other options that do what I need, but so far I'm not seeing any.

    • Edited by Rob McCready Friday, October 29, 2010 5:52 PM remove empty lines at bottom
    Friday, October 29, 2010 5:51 PM
  • I believe the ReportViewer.Enter event (inherited from Control) will do what you want.  I implemented a quick test application and I am seeing the event fire when I click anywhere in the ReportViewer, even before loading a report definition.
    Sunday, October 31, 2010 5:12 PM
    Moderator
  • I tried that and it only seems to fire the first time the ReportViewer is clicked not any subsequent times.

    So with two ReportViewer instances on a dashboard:

    1) Click the first instance, Enter fires and it is selected.

    2) Click on the second instance, Enter fires and it is selected.

    3) Click back on the first instance, nothing...

    In my case we are working with a WPF application so the ReportViewer controls are hosted in a WinFormsHost element. I added a Leave event handler and it is not fired at all until the tab is closed. Seems like the WinFormsHost is isolating the ReportViewer to the point that it has no idea what else is going on outside of its imediate host.

    Tuesday, November 2, 2010 6:28 AM
  • Rob, thank you for taking the time to figure this out and write a response to the post.  As you noted, a working kludge is better than an non-working theory, and I agree that knowing someone clicked somewhere on the control has great value in this case & I wish Microsoft's Report Viewer development team would be willing to support it (even if it is theoretically not perfect and doesn't "surface enough information", whatever that means.)

    Brian, thank you for presenting Microsoft's reason this doesn't exist.  It would have been helpful to get this response last year when I made the post as I gave up on the approach altogether.  Now I will be able to develop that application.


    Scott D Duncan
    Thursday, December 30, 2010 4:09 PM
  • I have a scenario where I have multiple report viewer controls on a Windows Form arranged in a grid.

    I was hoping the Click event would be actioned by the viewer so it could maximise itself to fill up the whole form and then a subsequent click would put it back to it's normal size i.e. allowing the user to "Zoom" to a particular report if they wished to and then put it back.

    It seems incomprehensible that this control has a Click event defined which never fires..??  Surely it would be better to remove it altogether so it's obvious it's not available if you are unable to reliably implement it?

    Wednesday, September 13, 2017 10:23 PM