有没有办法为 Winforms reportViewer 控件实现自定义上下文菜单?
Is there a way to implement a custom context menu for the Winforms reportViewer control?
我正在尝试为 WinForms.ReportViewer 控件实现自定义上下文菜单。如果用户在控件最顶部的 ReportViewer 控件的“工具栏”区域中单击鼠标右键,我可以让我的自定义菜单显示,但是当单击显示实际报告数据的控件的主要部分时,默认ReportViewer 显示附带的上下文菜单。有没有办法让我的上下文菜单替换默认菜单?
我搜索了 ReportViewer 的控件集合,none 其中有一个 ContextMenuStrip。如果重要,ReportViewer 控件版本为 15.0.0.0.
private void CreateContextMenu()
{
ContextMenuStrip menuStrip = new ContextMenuStrip();
ToolStripMenuItem menuItem = new ToolStripMenuItem("Exit");
menuItem.Click += new EventHandler(MenuItem_Click);
menuItem.Name = "Exit";
menuStrip.Items.Add(menuItem);
// This makes no difference.
//this.reportViewer1.ContextMenu = null;
this.reportViewer1.ContextMenuStrip = menuStrip;
}
private void MenuItem_Click(object sender, EventArgs e)
{
ToolStripItem menuItem = (ToolStripItem)sender;
if(menuItem.Name == "Exit")
{
Application.Exit();
}
}
是的,您可以替换报告的默认设置 ContextMenuStrip
。您需要获取包含并显示默认 CMS 的渲染器容器。 ReportViewer
控件树中唯一具有 CMS 的控件是 ReportPanel
类型的无名控件。我们可以利用这个事实来获得控制权并替换 CMS。
解决方案 1
目标面板没有name/key直接通过ControlCollection.Find
方法获取。但是,它的父项确实有一个名称 winRSviewer
。所以你可以这样写:
// +
// using System.Linq;
// ...
var c = reportViewer1.Controls.Find("winRSviewer", true)
.FirstOrDefault()?.Controls.OfType<Control>()
.FirstOrDefault(x => x.ContextMenuStrip != null);
if (c != null) c.ContextMenuStrip = contextMenuStrip1;
解决方案 2
使用递归函数获取目标控件:
private void SomeCaller()
{
var c = GetChildren(reportViewer1).FirstOrDefault(x => x.ContextMenuStrip != null);
if (c != null) c.ContextMenuStrip = contextMenuStrip1;
}
private IEnumerable<Control> GetChildren(Control parent) => parent.Controls
.Cast<Control>().Concat(parent.Controls
.Cast<Control>().SelectMany(GetChildren));
解决方案 3
创建一个新的class并继承自ReportViewer
控件。添加一个 属性 允许您在默认 CMS 和您选择的 CMS 之间切换。
public class ReportViewerEx : ReportViewer
{
private readonly Control reportPanel;
private readonly ContextMenuStrip defaultCMS;
public ReportViewerEx() : base()
{
reportPanel = GetChildren(this).FirstOrDefault(x => x.ContextMenuStrip != null);
if (reportPanel != null) defaultCMS = reportPanel.ContextMenuStrip;
}
private ContextMenuStrip customCMS;
[DefaultValue(null)]
public ContextMenuStrip ReportPanelContextMenuStrip
{
get => customCMS;
set
{
customCMS = value;
if (reportPanel != null) reportPanel.ContextMenuStrip = value ?? defaultCMS;
}
}
private IEnumerable<Control> GetChildren(Control parent) => parent.Controls
.Cast<Control>().Concat(parent.Controls
.Cast<Control>().SelectMany(GetChildren));
}
构建和删除一个实例。从下拉列表中找到 window 到 select 属性中的 ReportPanelContextMenuStrip
不同的 CMS。重置 属性 以使用默认 CMS。或者,通过代码设置 属性。 null
重置。
我正在尝试为 WinForms.ReportViewer 控件实现自定义上下文菜单。如果用户在控件最顶部的 ReportViewer 控件的“工具栏”区域中单击鼠标右键,我可以让我的自定义菜单显示,但是当单击显示实际报告数据的控件的主要部分时,默认ReportViewer 显示附带的上下文菜单。有没有办法让我的上下文菜单替换默认菜单?
我搜索了 ReportViewer 的控件集合,none 其中有一个 ContextMenuStrip。如果重要,ReportViewer 控件版本为 15.0.0.0.
private void CreateContextMenu()
{
ContextMenuStrip menuStrip = new ContextMenuStrip();
ToolStripMenuItem menuItem = new ToolStripMenuItem("Exit");
menuItem.Click += new EventHandler(MenuItem_Click);
menuItem.Name = "Exit";
menuStrip.Items.Add(menuItem);
// This makes no difference.
//this.reportViewer1.ContextMenu = null;
this.reportViewer1.ContextMenuStrip = menuStrip;
}
private void MenuItem_Click(object sender, EventArgs e)
{
ToolStripItem menuItem = (ToolStripItem)sender;
if(menuItem.Name == "Exit")
{
Application.Exit();
}
}
是的,您可以替换报告的默认设置 ContextMenuStrip
。您需要获取包含并显示默认 CMS 的渲染器容器。 ReportViewer
控件树中唯一具有 CMS 的控件是 ReportPanel
类型的无名控件。我们可以利用这个事实来获得控制权并替换 CMS。
解决方案 1
目标面板没有name/key直接通过ControlCollection.Find
方法获取。但是,它的父项确实有一个名称 winRSviewer
。所以你可以这样写:
// +
// using System.Linq;
// ...
var c = reportViewer1.Controls.Find("winRSviewer", true)
.FirstOrDefault()?.Controls.OfType<Control>()
.FirstOrDefault(x => x.ContextMenuStrip != null);
if (c != null) c.ContextMenuStrip = contextMenuStrip1;
解决方案 2
使用递归函数获取目标控件:
private void SomeCaller()
{
var c = GetChildren(reportViewer1).FirstOrDefault(x => x.ContextMenuStrip != null);
if (c != null) c.ContextMenuStrip = contextMenuStrip1;
}
private IEnumerable<Control> GetChildren(Control parent) => parent.Controls
.Cast<Control>().Concat(parent.Controls
.Cast<Control>().SelectMany(GetChildren));
解决方案 3
创建一个新的class并继承自ReportViewer
控件。添加一个 属性 允许您在默认 CMS 和您选择的 CMS 之间切换。
public class ReportViewerEx : ReportViewer
{
private readonly Control reportPanel;
private readonly ContextMenuStrip defaultCMS;
public ReportViewerEx() : base()
{
reportPanel = GetChildren(this).FirstOrDefault(x => x.ContextMenuStrip != null);
if (reportPanel != null) defaultCMS = reportPanel.ContextMenuStrip;
}
private ContextMenuStrip customCMS;
[DefaultValue(null)]
public ContextMenuStrip ReportPanelContextMenuStrip
{
get => customCMS;
set
{
customCMS = value;
if (reportPanel != null) reportPanel.ContextMenuStrip = value ?? defaultCMS;
}
}
private IEnumerable<Control> GetChildren(Control parent) => parent.Controls
.Cast<Control>().Concat(parent.Controls
.Cast<Control>().SelectMany(GetChildren));
}
构建和删除一个实例。从下拉列表中找到 window 到 select 属性中的 ReportPanelContextMenuStrip
不同的 CMS。重置 属性 以使用默认 CMS。或者,通过代码设置 属性。 null
重置。