DGV CellValidating event not letting new forms be focused

G

Guest

I have a form with a DataGridView in an MDI application that handles the
CellValidating event. If I set DataGridViewCellValidatingEventArgs.Cancel to
true, I can't navigate off the cell within the form as expected. However, If
I use the MDIParent to create a new instance if the child form, the focus
remains on the error cell in the first form even with the new form in the
foreground.

The behavior that I would like to create here would be for the focus to
remain in the error cell when that form is in focus, but for new forms to be
able to be created and focused on their own. What is the best way to achieve
this?

Thanks in advance.
 
L

Linda Liu [MSFT]

Hi,

Sorry that I may not understand your scenario exactly.

I performed a test on this issue. I create a WinForm application project
and add three forms(Form1, Form2, and Form3) in the project. I set the
IsMdiContainer property of Form1 to True. Add a Button on Form1 and a
DataGridView on Form2.

Add the following code in the Form1's Load event handler:
private void Form1_Load(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.MdiParent = this;
frm.Show();
}

Add the following code in the Click event handler of the button on Form1:
private void button1_Click(object sender, EventArgs e)
{
Form3 frm = new Form3();
frm.MdiParent = this;
frm.Show();
}

In Form2, add the following code:

public Form2()
{
InitializeComponent();
this.dataGridView1.CellValidating += new
DataGridViewCellValidatingEventHandler(dataGridView1_CellValidating);
}
void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
e.Cancel = true;
}

Build the project and run it. Form2 is shown as an MDI child with a
DataGridView in it. I click a cell within the DataGridView and then can not
move the focus out of the cell, because I have set the Cancel property of
the DataGridViewCellValidatingEventArgs parameter to true in the
DataGridView's CellValidating event handler.

At this time, I could still click the button on the MDI parent, but without
effect, i.e. Form3 isn't opened after I click the button.
However, If I use the MDIParent to create a new instance if the child
form, the focus remains on the error cell in the first form even with the
new form in the foreground.

Could you please tell me how the new form is created and shown?


Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Linda,

This is very interesting. I duplicated what you did and got the behavior
that you described. I then added a ToolStrip and ToolStripButton and used
the ToolStripButton's click event handler instead of Button1. Form3 opened
on top of Form2 with the focus staying on Form2. Do you know why the exact
same code causes different behavior when invoked from a ToolStripButton's
event handler?

Thanks,
Loring
 
L

Linda Liu [MSFT]

Hi Loring,

Thank you for your prompt response.

I performed a test adding a ToolStrip and a ToolStripButton on the MDI
parent, and found that I could open Form3 via the ToolStripButton when
Form2 is shown.

I add the following statements to check when the event handlers are called:

class Form1:Form
{
private void toolStripButton1_Click(object sender, EventArgs e)
{
Console.WriteLine("toolstrip button click");
Form3 frm = new Form3();
frm.MdiParent = this;
frm.Show();
}

private void button1_Click(object sender, EventArgs e)
{
Console.WriteLine("button click");
Form3 frm = new Form3();
frm.MdiParent = this;
frm.Show();
}
}

class Form2:Form
{
void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
Console.WriteLine("cell validating");
e.Cancel = true;
}
}

When I click the button on the MDI parent, I see the following output:
cell validating

When I click the ToolStripButton in the MDI parent, I see the following
output:
toolstrip button click

In fact, when a button is clicked, the button will get focused. In this
case, the focus will be taken from the DataGridView, which in turn raise
the CellValidating event , however, the Cancel property of the
DataGridViewCellValidatingEventArgs parameter is set to true, so the
operation always fails.

On the contrary, when a ToolStripButton is clicked, the ToolStripButton
doesn't take the focus, because it is a component not a control. So the
operation succeeds.

As for your original question, I think it may be difficult to determine
what operation is attempting to take the focus from the DataGridView.

In addition, I'm sorry to say that I don't think it's a good practice to
allow the user to focus on another MDI child while there's an error in the
DataGridView on an MDI child.

If you have any concerns, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Thank you for clarifying the difference in focusing behavior between controls
and components. It's making more sense now.

On a UI philosophical note, I'm not sure that I agree with you that what I
am trying to do is bad practice, I have examples of Microsoft applications
that do similar things with grids and forms, but let's say I can't allow
users to focus a second MDI child with DGV errors on the first. I could
conditionally show the second form when the ToolStripButton is clicked, but
how would you recommend detecting first form's errors in the MDIParent?

Thanks,
Loring



Thanks,
Loring
 
L

Linda Liu [MSFT]

Hi Loring,

Thank you for your feedback.

I think a workaround of checking whether there's an error in a DataGridView
is to send the Enter key to the DataGridView, in order to get the
CellValidating event of the DataGridView raised.

We could add a flag indicating whether there's invalid data in the
DataGridView in the MDI child form and set this flag to true in the
CellValidating event handler when there's invalid data.

Note that the we should ensure the CellValidating event is handled(so as to
set the flag to a correct value) before we judge the value of the flag in
the MDI parent. I use a Timer to solve this problem, i.e. in the
ToolStripButton's Click event handler, call a method to invoke the
CellValidating event of the DataGridView, and then start a timer. In the
timer's Tick event handler, judge the value of the flag and determine if
another MDI child form should be opened.

The following is a sample. Form1 is the MDI parent. Form2 and Form3 are MDI
child forms. There's a DataGridView on Form2.

public partial class Form1 : Form
{
Form2 frm2;
private void Form1_Load(object sender, EventArgs e)
{
frm2 = new Form2();
frm2.MdiParent = this;
frm2.Show();
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
frm2.InvokeValidating();
System.Windows.Forms.Timer timer = new Timer();
timer.Interval = 10;
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}

void timer_Tick(object sender, EventArgs e)
{
Timer timer = (Timer)sender;
timer.Stop();
timer.Dispose();
timer = null;
if (!frm2.HasDirtyData)
{
Form3 frm = new Form3();
frm.MdiParent = this;
frm.Show();
}
}
}

public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
this.dataGridView1.CellValidating+=new
DataGridViewCellValidatingEventHandler(dataGridView1_CellValidating);

}
private bool hasDirtyData = false;
public bool HasDirtyData
{
get { return hasDirtyData; }
set { hasDirtyData = value; }
}
public void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
hasDirtyData = true;
e.Cancel = true;
}

public void InvokeValidating()
{
if (!this.hasDirtyData)
{
this.dataGridView1.Focus();
SendKeys.Send("{Enter}");
}
}

private void Form2_Load(object sender, EventArgs e)
{
this.dataGridView1.RowCount = 3;
}
}

Hope this helps.
If you have any question, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
L

Linda Liu [MSFT]

Hi Loring,

How about the problem now?

If you have any question, please feel free to let me know.

Thank you for using our MSDN Managed Newsgroup Support Service!

Sincerely,
Linda Liu
Microsoft Online Community Support
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top