我在ReportViewer
应用程序中使用WinForms
控件来显示RDLC
报告。
表单非常简单(它只包含reportviewer,没有其他内容),通常效果很好。
但是有一个恼人的问题:当用户使用鼠标滚轮更改页面时,每个向上/向下滚动向后/向后翻页,而不是一页。
这使得阅读报告非常烦人,当然。为什么这样做,如何让它只滚动一页呢?
编辑:通过进一步测试,我可以确认ReportViewer
的{{1}}事件为滚轮的每个“勾号”触发两次。还是不知道为什么......
答案 0 :(得分:1)
这是一个非常有趣的问题。
ReportViewer的滚动触发器可能会使用来自正常displaymode的分页,无论它是如何定义的。在此displaymode中,记者只会在明确定义时添加分页符,或者添加由InteractiveSize
属性确定的软分页符。
您可以将InteractiveSize
属性设置为与PageSize
相同,这样您就可以使用DisplayMode.Normal
并保持与DisplayMode.PrintLayout
相同的分页功能
然而,这可能仍然无法解决滚动问题,因为ReportViewer滚动也可能忽略软分页符。这意味着它首先在单个页面上滚动,然后应用分页,从而可以跳过页面。
如果是这种情况,那么我相信您唯一的另一个选择是编写自己的ReportViewer自定义版本并尝试修复它。
修改强> 事实证明滚动行为对我来说是正常的。这意味着它必须是特定于您的环境的问题。您使用的是哪个版本和框架?
您可以通过捕捉滚动事件并自行触发PageNavigation
来轻松解决此问题。
答案 1 :(得分:1)
这是我的解决方案,在VB中。它也可以与按钮导航一起使用。
首先,我们必须将处理程序添加到报表查看器的导航按钮中。
我的控制报表查看器的名称是“ reportViewer
”
Private Sub Print_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim ts As ToolStrip = TryCast(reportViewer.Controls.Find("toolstrip1", True).First, ToolStrip)
If Not ts Is Nothing Then
For Each tsb As ToolStripItem In ts.Items
If TypeOf tsb Is ToolStripButton AndAlso
(TryCast(tsb, ToolStripButton).Name = "firstPage" Or
TryCast(tsb, ToolStripButton).Name = "lastPage" Or
TryCast(tsb, ToolStripButton).Name = "previousPage" Or
TryCast(tsb, ToolStripButton).Name = "nextPage") Then
AddHandler tsb.Click, AddressOf tsb_Click
End If
Next
End If
End Sub
然后是核心
Dim scrolled As New List(Of Integer)
Private Sub reportViewer_PageNavigation(sender As Object, e As PageNavigationEventArgs) Handles reportViewer.PageNavigation
scrolled.Add(e.NewPage)
End Sub
Private Sub reportViewer_MouseWheel(sender As Object, e As MouseEventArgs) Handles reportViewer.MouseWheel
If scrolled.Count > 1 Then
reportViewer.CurrentPage = scrolled.Item(scrolled.Count - 2)
scrolled.Clear()
ElseIf scrolled.Count = 1 Then
reportViewer.CurrentPage = scrolled.Item(scrolled.Count - 1)
scrolled.Clear()
End If
End Sub
Public Sub tsb_Click(ByVal sender As Object, ByVal e As EventArgs)
scrolled.Clear()
End Sub
希望这会有所帮助
答案 2 :(得分:1)
编辑:仅当您的应用程序以32位运行时,原始堆栈跟踪才显示为true。对于64位,第二个调用中只有三行没有出现在第一行中,此处列出。
at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
处理这两种情况的更新代码是
private void Viewer_PageNavigation(object sender, PageNavigationEventArgs e) => e.Cancel = Environment.StackTrace.Contains("DefWndProc");
这仍然是一个丑陋的骇客,但确实有效。
要查看实际情况,您需要禁用“ Just My Code”并调试到Framework中。通过订阅ReportViewer.PageNavigation
事件并设置断点,您可以看到导航发生了两次。第一次是由WM_MOUSEWHEEL
的一个称为ReportViewer
的组件处理的RenderingPanel
消息触发的。该组件的OnMouseWheel
方法仅调用ReportPanel.OnMouseWheel
,它执行滚动/导航。但是,相同的窗口消息随后传递到ReportPanel
,导致ReportPanel.OnMouseWheel
被再次调用。本质上,每个低级滚轮消息都会导致两次滚动。您可以通过在第一次通话中插入ReportPanel.OnMouseWheel
并设置e.Handled = true
来进行测试。在这种情况下,不会再次调用ReportPanel.OnMouseWheel
。
请注意,我们正在谈论ReportViewer
内部组件的鼠标滚轮事件,这与控件的滚轮事件不同。尽管具有所有内部功能,ReportViewer.MouseWheel
仅引发一次,并且在两次PageNavigation
事件之后都会发生。
最重要的是,控件始终将两次Wheel消息处理两次。通常,您不会注意到这一点。如果向下滚动并且报表滚动10%,您怎么知道它只应该滚动5%但实际上滚动了两次?但是,如果您的缩放级别足以使单个滚轮滚动等于整页,则...动臂...每个滚轮滚动两页。但是,我还没有确定为什么这只是打印预览模式下的问题。
没有干净的解决方案。我想到的最好的办法是检查ReportViewer.PageNavigation
内的堆栈,如果事件是由RenderingPanel
引起的,则忽略它。这样的修复看起来像这样:
/* The ReportViewer control is composed of several sub-controls. One of those is a RenderingPanel, whose OnMouseWheel method gets called
* by the Framework in response to a window message. That method simply calls ReportPanel.OnMouseWheel, which performs scroll/navigation.
* However, ReportPanel.OnMouseWheel is subsequently called again by the Framework in response to the same window message resulting in all
* wheel events being processed twice. While this results in each wheel scroll being twice as large as it should be, it is generally not
* noticeable (how would you know that the scroll distance should be half of what it is?) unless the zoom level is sufficient (i.e. Whole Page)
* that a single wheel event results in an entire page navigation. In this case, two pages are flipped instead of one. In order to avoid this,
* we simply cancel any page navigation that was caused by the RenderingPanel's handling of the wheel event. */
private void Viewer_PageNavigation(object sender, PageNavigationEventArgs e) => e.Cancel = Environment.StackTrace.Contains("ReportPanel.RenderingPanel.OnMouseWheel");
答案 3 :(得分:-1)
我有同样的问题。每次使用鼠标滚轮时,PageNavigation事件都会触发两次。
我决定自定义PageNavigation事件:
bool scroll = true;
private void ReportViewer_PageNavigation(object sender, PageNavigationEventArgs e)
{
if (!scroll)
e.Cancel = true;
scroll = !scroll;
}