views:

1358

answers:

5

Hi,

How do I implement a Copy menu item in a Windows application written in C#/.NET 2.0?

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.

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.

A: 

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.

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.

Geoffrey Chetwood
A: 

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.

Drejc
+1  A: 

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:

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:

((FormFoo)this.ActiveMDIChild).GetCopiedData();

Assuming the GetCopiedData function will have the form-specific implementation to detect what text should be copied to the clipboard.

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:

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.

+4  A: 

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.

    /// <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?...)
        {
        }
    }
Petteri
A: 

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.

I got around this by implementing the following handler for my DataGridView:-

private void dataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)

{

 if (e.Button == MouseButtons.Right)
 {
      dataGridView.Focus();

      dataGridView.CurrentCell = dataGridView[e.ColumnIndex, e.RowIndex];
 }

}