How do I implement a Copy menu item in a Windows application written in C#/.NET 2.0?
如何在用C#/ .NET 2.0编写的Windows应用程序中实现“复制”菜单项?
I want to let the user to mark some text in a control and then select the Copy menu item from an Edit menu in the menubar of the application and then do a Paste in for example Excel.
我想让用户在控件中标记一些文本,然后从应用程序的菜单栏中的“编辑”菜单中选择“复制”菜单项,然后执行粘贴,例如Excel。
What makes my head spin is how to first determine which child form is active and then how to find the control that contains the marked text that should be copied to the clipboard.
让我头脑旋转的原因是如何首先确定哪个子表单处于活动状态,然后如何找到包含应该复制到剪贴板的标记文本的控件。
Help, please.
5 个解决方案
#1
5
With the aid of some heavy pair programming a colleague of mine and I came up with this, feel free to refactor.
在我和我的一位同事编程的帮助下,我想出了这个,随意重构。
The code is placed in the main form. The copyToolStripMenuItem_Click method handles the Click event on the Copy menu item in the Edit menu.
代码放在主窗体中。 copyToolStripMenuItem_Click方法处理“编辑”菜单中“复制”菜单项上的“单击”事件。
/// <summary>
/// Recursively traverse a tree of controls to find the control that has focus, if any
/// </summary>
/// <param name="c">The control to search, might be a control container</param>
/// <returns>The control that either has focus or contains the control that has focus</returns>
private Control FindFocus(Control c)
{
foreach (Control k in c.Controls)
{
if (k.Focused)
{
return k;
}
else if (k.ContainsFocus)
{
return FindFocus(k);
}
}
return null;
}
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
Form f = this.ActiveMdiChild;
// Find the control that has focus
Control focusedControl = FindFocus(f.ActiveControl);
// See if focusedControl is of a type that can select text/data
if (focusedControl is TextBox)
{
TextBox tb = focusedControl as TextBox;
Clipboard.SetDataObject(tb.SelectedText);
}
else if (focusedControl is DataGridView)
{
DataGridView dgv = focusedControl as DataGridView;
Clipboard.SetDataObject(dgv.GetClipboardContent());
}
else if (...more?...)
{
}
}
#2
1
To determine which window is open, you can query the Form.ActiveMDIChild property to get a reference to the currently active window. From there, you can do one of two things:
要确定打开哪个窗口,可以查询Form.ActiveMDIChild属性以获取对当前活动窗口的引用。从那里,你可以做以下两件事之一:
1) If you create your own custom Form class (FormFoo for example) that has a new public member function GetCopiedData(), then inherit all of your application's child forms from that class, you can just do something like this:
1)如果您创建自己的自定义Form类(例如FormFoo),它具有新的公共成员函数GetCopiedData(),然后从该类继承所有应用程序的子表单,您可以执行以下操作:
((FormFoo)this.ActiveMDIChild).GetCopiedData();
Assuming the GetCopiedData function will have the form-specific implementation to detect what text should be copied to the clipboard.
假设GetCopiedData函数将具有特定于表单的实现,以检测应将哪些文本复制到剪贴板。
or
2) You can use inheritance to detect the type of form that is active, and then do something to get the copied data depending on the type of form:
2)您可以使用继承来检测活动表单的类型,然后根据表单类型执行某些操作来获取复制的数据:
Form f = this.ActiveMDIChild;
if(f is FormGrid)
{
((FormGrid)f).GetGridCopiedData();
} else if(f is FormText) {
((FormText)f).GetTextCopiedData();
}
etc.
That should get you started with finding the active window and how to implement a copy function. If you need more help copying out of a GridView, it may be best to post another question.
这应该让您开始寻找活动窗口以及如何实现复制功能。如果您需要更多帮助从GridView复制,最好发布另一个问题。
#3
0
Why not extending the control, so the control itself provides the data which should be copied into the clipboard.
为什么不扩展控件,所以控件本身提供应该复制到剪贴板的数据。
Take a look at ApplicationCommands documentation.
看一下ApplicationCommands文档。
#4
0
If the form is tabbed and the target control is a DataGridView, it's sometimes possible for the Form's TabControl to be returned as the active control, using the above method, when the DataGridView is right clicked upon.
如果表单是选项卡并且目标控件是DataGridView,则有时可以使用上面的方法在右键单击DataGridView时将Form的TabControl作为活动控件返回。
I got around this by implementing the following handler for my DataGridView:-
我通过为我的DataGridView实现以下处理程序来解决这个问题: -
private void dataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
private void dataGridView_CellMouseDown(object sender,DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
dataGridView.Focus();
dataGridView.CurrentCell = dataGridView[e.ColumnIndex, e.RowIndex];
}
}
#5
-1
It seems to me that you might be better off breaking this into smaller tasks/questions. You have a few issues you are stuck on from the way it sounds.
在我看来,你可能最好将其分解为更小的任务/问题。从听起来的方式来看,你遇到了一些问题。
You have multiple 'child' windows open. Is this an MDI application? When an action is performed on one of those child windows, it should fire an event in that window's event handlers. That is your first thing to set up. If this is a datagridview I would suggest a simple test to start. Try trapping the DataGridView.SelectionChanged event. Just throw in something like MessageBox.Show("I copied your datas!");
for now.
您打开了多个“子”窗口。这是MDI应用程序吗?当在其中一个子窗口上执行操作时,它应该在该窗口的事件处理程序中触发事件。这是你设置的第一件事。如果这是一个datagridview,我会建议一个简单的测试开始。尝试捕获DataGridView.SelectionChanged事件。只需抛出像MessageBox.Show(“我复制你的数据!”);目前。
This should get you started where you will at least understand how this event will be raised to you.
这应该让你开始,至少你将了解如何向你提出这个事件。
From here, we will need to know a little more about your datagrid, and the rows and child controls in those rows. Then we can likely create events in the render events that will be raised at the appropriate times, with the appropriate scope.
从这里开始,我们需要了解有关您的数据网格以及这些行中的行和子控件的更多信息。然后我们可以在适当的范围内在适当的时间创建渲染事件中的事件。
#1
5
With the aid of some heavy pair programming a colleague of mine and I came up with this, feel free to refactor.
在我和我的一位同事编程的帮助下,我想出了这个,随意重构。
The code is placed in the main form. The copyToolStripMenuItem_Click method handles the Click event on the Copy menu item in the Edit menu.
代码放在主窗体中。 copyToolStripMenuItem_Click方法处理“编辑”菜单中“复制”菜单项上的“单击”事件。
/// <summary>
/// Recursively traverse a tree of controls to find the control that has focus, if any
/// </summary>
/// <param name="c">The control to search, might be a control container</param>
/// <returns>The control that either has focus or contains the control that has focus</returns>
private Control FindFocus(Control c)
{
foreach (Control k in c.Controls)
{
if (k.Focused)
{
return k;
}
else if (k.ContainsFocus)
{
return FindFocus(k);
}
}
return null;
}
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
Form f = this.ActiveMdiChild;
// Find the control that has focus
Control focusedControl = FindFocus(f.ActiveControl);
// See if focusedControl is of a type that can select text/data
if (focusedControl is TextBox)
{
TextBox tb = focusedControl as TextBox;
Clipboard.SetDataObject(tb.SelectedText);
}
else if (focusedControl is DataGridView)
{
DataGridView dgv = focusedControl as DataGridView;
Clipboard.SetDataObject(dgv.GetClipboardContent());
}
else if (...more?...)
{
}
}
#2
1
To determine which window is open, you can query the Form.ActiveMDIChild property to get a reference to the currently active window. From there, you can do one of two things:
要确定打开哪个窗口,可以查询Form.ActiveMDIChild属性以获取对当前活动窗口的引用。从那里,你可以做以下两件事之一:
1) If you create your own custom Form class (FormFoo for example) that has a new public member function GetCopiedData(), then inherit all of your application's child forms from that class, you can just do something like this:
1)如果您创建自己的自定义Form类(例如FormFoo),它具有新的公共成员函数GetCopiedData(),然后从该类继承所有应用程序的子表单,您可以执行以下操作:
((FormFoo)this.ActiveMDIChild).GetCopiedData();
Assuming the GetCopiedData function will have the form-specific implementation to detect what text should be copied to the clipboard.
假设GetCopiedData函数将具有特定于表单的实现,以检测应将哪些文本复制到剪贴板。
or
2) You can use inheritance to detect the type of form that is active, and then do something to get the copied data depending on the type of form:
2)您可以使用继承来检测活动表单的类型,然后根据表单类型执行某些操作来获取复制的数据:
Form f = this.ActiveMDIChild;
if(f is FormGrid)
{
((FormGrid)f).GetGridCopiedData();
} else if(f is FormText) {
((FormText)f).GetTextCopiedData();
}
etc.
That should get you started with finding the active window and how to implement a copy function. If you need more help copying out of a GridView, it may be best to post another question.
这应该让您开始寻找活动窗口以及如何实现复制功能。如果您需要更多帮助从GridView复制,最好发布另一个问题。
#3
0
Why not extending the control, so the control itself provides the data which should be copied into the clipboard.
为什么不扩展控件,所以控件本身提供应该复制到剪贴板的数据。
Take a look at ApplicationCommands documentation.
看一下ApplicationCommands文档。
#4
0
If the form is tabbed and the target control is a DataGridView, it's sometimes possible for the Form's TabControl to be returned as the active control, using the above method, when the DataGridView is right clicked upon.
如果表单是选项卡并且目标控件是DataGridView,则有时可以使用上面的方法在右键单击DataGridView时将Form的TabControl作为活动控件返回。
I got around this by implementing the following handler for my DataGridView:-
我通过为我的DataGridView实现以下处理程序来解决这个问题: -
private void dataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
private void dataGridView_CellMouseDown(object sender,DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
dataGridView.Focus();
dataGridView.CurrentCell = dataGridView[e.ColumnIndex, e.RowIndex];
}
}
#5
-1
It seems to me that you might be better off breaking this into smaller tasks/questions. You have a few issues you are stuck on from the way it sounds.
在我看来,你可能最好将其分解为更小的任务/问题。从听起来的方式来看,你遇到了一些问题。
You have multiple 'child' windows open. Is this an MDI application? When an action is performed on one of those child windows, it should fire an event in that window's event handlers. That is your first thing to set up. If this is a datagridview I would suggest a simple test to start. Try trapping the DataGridView.SelectionChanged event. Just throw in something like MessageBox.Show("I copied your datas!");
for now.
您打开了多个“子”窗口。这是MDI应用程序吗?当在其中一个子窗口上执行操作时,它应该在该窗口的事件处理程序中触发事件。这是你设置的第一件事。如果这是一个datagridview,我会建议一个简单的测试开始。尝试捕获DataGridView.SelectionChanged事件。只需抛出像MessageBox.Show(“我复制你的数据!”);目前。
This should get you started where you will at least understand how this event will be raised to you.
这应该让你开始,至少你将了解如何向你提出这个事件。
From here, we will need to know a little more about your datagrid, and the rows and child controls in those rows. Then we can likely create events in the render events that will be raised at the appropriate times, with the appropriate scope.
从这里开始,我们需要了解有关您的数据网格以及这些行中的行和子控件的更多信息。然后我们可以在适当的范围内在适当的时间创建渲染事件中的事件。