DataGridView problem

I have DataGridView control with 2 editable columns. 1 of them (column 1) should accept only digits and decimal point, another (column 2) only digits.

void dGr_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dGr.CurrentCell.ColumnIndex == 1)
{
if (e.Control is TextBox)
{
TextBox tb = e.Control as TextBox;
tb.KeyPress += new KeyPressEventHandler(tb_KeyPress);
}
}
else if (dGr.CurrentCell.ColumnIndex == 2)
{
if (e.Control is TextBox)
{
TextBox tb = e.Control as TextBox;
tb.KeyPress += new KeyPressEventHandler(tb_KeyPress2);
}
}
}

void tb_KeyPress(object sender, KeyPressEventArgs e)
{
if (!(char.IsDigit(e.KeyChar)))
{
if (e.KeyChar != '' && e.KeyChar != '.') //allow the backspace key and decimal point
e.Handled = true;
}
}

void tb_KeyPress2(object sender, KeyPressEventArgs e)
{
if (!(char.IsDigit(e.KeyChar)))
{
if (e.KeyChar != '')
e.Handled = true;
}
}

The problem: at the beginning column 1 accepts only digits and decimal point as intended, but after I try to edit column 2 cells, column 1 stops taking a decimal point and behaves exactly like column 2. Any idea why it happens?


Also -
I'd like to change a column's background color to yellow.

dGr.Columns["MyColumn"].DefaultCellStyle.BackColor = Color.LightYellow;

That statement will not change the alternating rows DefaultCellStyle. So I have only half of all rows with yellow background. How to fix that?






«1

Comments

  • The reason why it seems your event handler for one column is bleeding over into the other column is because the actual "textbox" used for editing in the datagrid view is recycled. You are actually adding more and more handlers to it every time it is shown according to this code.

    so after 3 edits to column 1, the column 1 handler is called 3 times every key press.

    after an edit to column 2, the column 1 handler is called 3 times and the column 2 handler is called 1 time per every key press.

    What you might do is assign the handler somewhere else - or only once to the textbox and inside the handler itself grab what the active column is and perform your logic there.


    as for the other part to your question - to override just a single columns behavior you can tap into the paint events of the cells and override the formatting manually.

    ><//~Psightoplasm`~
  • Yes thanks, I figured it out that the CellFormatting event does the trick:
    if (dGr.Columns[e.ColumnIndex].Name == "MyColumn")
    e.CellStyle.BackColor = Color.Yellow;

    But I'm not sure I understood how to fix the first problem.
    Can you elaborate please how to assign handler somewhere else?
  • Also - I think at some point you may just want to inherit the datagridviewtextcolumn and cells into your own classes so you can override functionality or add your own custom functionality all together and not have to rely on event handlers so much.

    ><//~Psightoplasm`~
  • what I meant by assign the handler somewhere else was to use a different event but I would really recomend just inheriting the column and cells into your own classes so you can just access the protected functionality directly and make it function however you want.

    This way you can even add a property onto the column that can turn on or off decimal points. It's an extra couple of files in your project, but I assure you that your code will be alot happier.

    also as a side note: you can use -= on an event handler to remove it from the firing queue - so whenever the textbox is hidden for example.

    ><//~Psightoplasm`~
  • thanks, I'll definitely try that later. Meanwhile I got a quick fix (from other forum)
    Changed
    if (e.KeyChar != '' && e.KeyChar != '.')
    e.Handled = true;

    To
    if (e.KeyChar != '' && e.KeyChar != '.')
    e.Handled = true;
    else
    e.Handled = false

    Apparently e.Handled doesn't have default but remembers its previous value.


  • if you want to know more
    Please click http://www.nowgoal.com/23.shtml
  • One more DataGridView question

    I add a check box column, and when I sort the DataGridView by clicking columns' headers it resets check box column values. Why does it happen and is there any way to preserve the values while sorting?
  • So short of seeing your application to figure out the problem (which I would rather not do, sorry) I would say if you are using a binding source or something, you might need to commit changes prior to a sort.

    Also: while it appears someone offered you a hack to fix your original problem, there is still a much more serious issue going on there.

    If you keep adding handlers to an event on an object (+= MyHandler...), every edit you make is going to slowly degrade your application's performance little by little.

    let's say one of your users has made 1000 edits - now for every single number they type into those fields, your handlers are being called 1000 times per event!

    At the very least - even though it's messy - you should be using a '-=' on the text box's event to remove the handler after the edit has been made.

    Just so you can see what is going on, try this:

    [code]
    void dGr_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
    if (dGr.CurrentCell.ColumnIndex == 1)
    {
    if (e.Control is TextBox)
    {
    TextBox tb = e.Control as TextBox;
    tb.KeyPress += delegate { MessageBox.Show("Handler Fired!"); };
    }
    }
    }

    [/code]

    Now make about 3 different edits in the column with an index of 1 -

    On your first edit: a message box will pop up once per key press.
    On your second edit: A message box will pop up twice per key press.
    on your third edit: A message box will pop up three times per key press.
    and so on...

    The reason why the hack you were given works is because the last handler that has been added just happens to be the right one for the column you are editing and is therefore the last one called and the last one to set your event arg values. The reason your event args seem to be retaining values between calls is because each call that is being made per event is sharing the same eventarg object and each one is setting values on it.

    ><//~Psightoplasm`~
  • Psightoplasm

    You are right I told previously that I'll definitely try later what you are suggesting...

    As for the check box column it's unbound and is the reason it gets unchecked on sorting (there is no source for that), so I'm not sure how to preserve checked values
  • I asked one of my co-workers and it sounds like if the checkbox column is not bound to anything then this will happen just as in issue with the datagridview - is there a reason you can't create a BindingList or something you can bind it to in order to retain the values?

    ><//~Psightoplasm`~
  • well, I add a checkbox column in order not to modify the database immediately. Just to check multiple roows and then click Update, Delete, or Reset buttons. I could probably create a bindinglist... or if I knew what events are fired on column's header click before and after sorting...

  • I tried to use BindingList but all cells are not editable now even if I set MyBindingList.AllowEdit to true. No sure what the difference is.

    Of course, it'd be easier instead of adding checkbox column, add true/false field in the database SELECT statement, but I use SQLIte which doesn't support boolean type.

    Here is my pretty basic code:

    private class Card
    {
    private String _card;
    private String _image, _note;
    private bool _check;

    public Card(String card, String image, String note, bool check)
    {
    _card = card;
    _image = image;
    _note = note;
    _check = check;
    }

    public String card { get { return _card; } }
    public String image { get { return _image; } }
    public String note { get { return _note; } }
    public bool check { get { return _check; } }
    }

    private BindingList CardList;

    and then after I get Dataset (ds)

    CardList = new BindingList();
    CardList.AllowEdit = true;

    for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
    {
    CardList.Add(new Card(ds.Tables[0].Rows[i].ItemArray[0].ToString(), ds.Tables[0].Rows[i].ItemArray[1].ToString(),
    ds.Tables[0].Rows[i].ItemArray[2].ToString(), false));
    }

    dGrCards.DataSource = CardList;

  • I think the problem is that your card class has only getters and not setters on the properties. This is why you can't edit them.

    you might also try doing this on the Check property (since you can't use boolean):

    [code]
    public class Card
    {
    public Card(string name, string image, string message, int check)
    {
    Card = name;
    Image = image;
    Note = message;
    _check = check;
    }

    public string Card { get; set; }
    public string Image { get; set; }
    public string Note { get; set; }

    // wrap your int value with a boolean property
    private int _check;
    public bool Check
    {
    get { return (_check > 0); }
    set { _check = value ? 1 : 0; }
    }

    // for saving to the db later
    public int GetCheckValue()
    {
    return _check;
    }
    }
    [/code]

    ><//~Psightoplasm`~
  • Yes, setters... but now columns are not sortable (headers click doesn't do anything)
  • I added Sortable BindingList inherited from BindingList. It's sorting the check box column fine but the feature I mentioned before (when datagridview is sorted automatically on the cell value edit) is lost. I probably can leave with that for now.

    Psightoplazm, thanks a lot for your time
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories