4

How can I make a button that can sendkeys into a datagridview (so I need to somehow return datagridview to its state prior to it losing focus)

I'll explain the problem

I have a form with a datagridview and some buttons

enter image description here

I can click the button and it will enter the corresponding letter,

dataGridView1.Focus();
SendKeys.Send("a");  //or m or z, depending on the text of the button.

The button is meant to be for entering data into datagridview. I could make it so it's enabled only when datagridview's enter method is called. When the button is clicked then the datagridview loses focus so I have to give it the focus again, prior to sending the key. Hence the two lines above.

I want the user to be able to use the buttons to enter data into datagrid.

The problem is, let's say I want the user to be able to enter the text "maz" I can't do it. I only get an individual a or m or z. And even if I could put a cell back into editable mode, i'd need to remember where the cursor was.. So if somebody typed asdf into a cell and put the cursor between d and f, and clicked m, i'd want it to say asdmf.

I don't know how to accomplish that.

I have an idea.. that maybe if there was a way of registering that the mouse was over a button and the click was pushed, but without losing focus on datagridview, then that would be one way that it could be done. I don't know how to do that though, and i'm interested in different ways.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
barlop
  • 12,887
  • 8
  • 80
  • 109
  • Is there a reason why it has to be sendkeys instead of modifying the contents of the cell, (or of the underlying bound object)? – peterG Apr 21 '16 at 14:10
  • I guess it could modify the contents of the cell but there's still the problem that clicking the button would cause a lose of focus thus losing the cursor position so if I wanted asdf to become asdmf I don't see how. – barlop Apr 21 '16 at 14:12

1 Answers1

6

Non-Selectable Button to Send Key like Virtual Keyboard

It's enough to make a non-selectable button and then handle it's click event and send key. This way these buttons can work like virtual keyboard keys and the focus will remain on the control which has focus while it sends the key to the focused control.

public class ExButton:Button
{
    public ExButton()
    {
        SetStyle(ControlStyles.Selectable, false);
    }
}

Then handle click event and send key:

private void exButton1_Click(object sender, EventArgs e)
{
    SendKeys.SendWait("A");
}

SetStyle extension method for a Control

Is there any way of calling SetStyle on a Control without using inheritance?

Yes, using Reflection, there is. Create this extension method:

public static class Extensions
{
    public static void SetStyle(this Control control, ControlStyles flags, bool value)
    {
        Type type = control.GetType();
        BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
        MethodInfo method = type.GetMethod("SetStyle", bindingFlags);
        if (method != null)
        {
            object[] param = { flags, value };
            method.Invoke(control, param);
        }
    }
}

Then use it this way, in your form Load event:

this.button1.SetStyle(ControlStyles.Selectable, false);

Then button1 will be non-selectable without inheritance.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • is there any way of doing `SetStyle(ControlStyles.Selectable, false);` on a button to make it non selectable, without using inheritance? – barlop Apr 21 '16 at 15:30
  • @barlop Yes, there is. I edited the post to make the answer for useful for you. – Reza Aghaei Apr 21 '16 at 16:20
  • By the way, since I couldn't find a duplicate question for **Is there any way of calling SetStyle on a Control without using inheritance?**, I think it's good to ask it as a new question and I'll post the edit there. This way the question will be more useful for future readers. – Reza Aghaei Apr 21 '16 at 16:21
  • I haven't had much practise using SetStyle, you could probably write a better question for "Is there any way of calling SetStyle on a Control without using inheritance?", because you have a deeper understanding of it, and then you could answer your own question. That would be very valuable for the SO/programming community. I'm sure your answer works but I will accept your answer once i've tried and tested it. – barlop Apr 21 '16 at 21:02
  • No problem, anyway, now the post contains two questions. – Reza Aghaei Apr 21 '16 at 21:06
  • i'd add that the setstyle line can be done anywhere, e.g. it can be done when the form with the buttons loads up. You don't need `public class ExButton:Button { public ExButton() { SetStyle(ControlStyles.Selectable, false); } }` you can skip that class and put the SetStyle line wherever. – barlop Sep 01 '16 at 14:50
  • `SetStyle` is protected ad can be called only for a control in the control class. You can't use it for another control. I created the extension method to enable you to call it against a control. – Reza Aghaei Sep 01 '16 at 14:53
  • I mean still calling setStyle on a Button control.. but can call button1.setStyle from wherever e.g. from within a form load. And you don't need that class that class you called ExButton. ,with the call in the constructor e.g. http://pastebin.com/raw/adkAAAb8 You can e.g. do the whole thing with just the form load and the extension class. In retrospect, that is what you were saying in your answer. I was just looking back at it and didn't realise. – barlop Sep 01 '16 at 18:25
  • Probably we are talking about the same thing. You can use either of these two options to call `SetStyle`: *1)* Inheritance *2)* That extension method – Reza Aghaei Sep 01 '16 at 18:34
  • Ugh. The extension method is a cute hack but should *never* be used in production code. Don’t break encapsulation for such trivial reasons. – Konrad Rudolph Jan 17 '17 at 15:09
  • @KonradRudolph Yes, it should be used carefully just in cases which it should. It's here in response of *Is there any way of calling SetStyle on a Control without using inheritance?* :) – Reza Aghaei Jan 17 '17 at 15:32
  • 1
    The code using reflection works just as well without putting it in an extension method. Maybe it's a bit much to introduce both concepts at once! – Bloopy Jun 08 '17 at 14:09
  • @Bloopy how would you do it without inheritance and without an extension method? – barlop Nov 09 '17 at 09:10
  • 1
    @barlop Remove the `this` so SetStyle takes the Control as a regular argument. Then if you put SetStyle in a class called Misc for example, you would call `Misc.SetStyle(button1, ControlStyles.Selectable, false)`. – Bloopy Nov 10 '17 at 12:02
  • @Bloopy It's better to keep it as extension method. Then you can simply call `button1.SetStyle(...)` which makes more sense. Extension methods are a feature of C# which have a lot of usage. For example all LINQ methods are extension methods. – Reza Aghaei Nov 10 '17 at 15:10
  • Perhaps, but I felt the need to point it out for people less familiar with C#. Your answer could mislead them into thinking that things like this can only be done with extensions. – Bloopy Nov 12 '17 at 01:31