我有一个简单的Winform示例,演示了会发生什么。
有一个带有两个RadioButtons的GroupBox。这两个按钮共享一个验证事件处理程序。表单上还有一个什么都不做的Button。没有连接任何事件。最后,有一个CheckBox控制传递验证的状态。检查通过并取消选中它失败。
当程序启动并且用户点击RadioButton时,验证事件不会触发。然后当我点击当前按钮以外的任何控件时,验证事件将触发。 NOP按钮让我可以点击CheckBox旁边的东西。
在此测试中,CheckBox表示传递验证的状态。
这不起作用,因为一旦我取消选中CheckBox然后单击单选按钮,焦点就会永远停滞不前。您无法将焦点集中到CheckBox以更改其状态。
原因是在焦点离开时始终调用Validating事件,而不是在单击RadioButton时调用。它看到“valdating”失败并取消该事件。
这显然是错误的做法。在初次点击时我应该做些什么来测试? Click事件在状态发生变化后发生。
我应该使用什么事件以便在更改RadioButton状态之前测试验证?然后,我可以在再次尝试之前离开按钮并解决问题。
这个例子是一个显示我死路的简化测试。我的真实世界的例子是两个RadioButtons选择DataGridView中两个相似表中的一个。这两个表是相关的,我希望它们在同一个TabPage上。当用户选择备用表时,我想在切换之前进行验证/确认。如果确认失败,我想取消单选按钮。
// Validate is called when the radio button is clicked and when it leaves the box
using System.ComponentModel;
using System.Windows.Forms;
namespace ValidateRadioButton
{
public partial class Form1 : Form
{
int count;
public Form1()
{
InitializeComponent();
}
private void radiobutton_Validating(object sender, CancelEventArgs e)
{
if (sender is RadioButton) {
// If box not checked, cancel radioButton change
// This becomes a Hotel California test, once unchecked you
// can never leave the control
e.Cancel = !chkAllowChange.Checked;
}
count++;
//Display the number of times validating is called in the title bar
//Demonstrates when the event is called
Text = count.ToString();
}
}
}
答案 0 :(得分:0)
我已经在测试项目中复制了您的表单,我想我知道发生了什么。
将Checked
的{{1}}属性设置为true将阻止任何控件设置它失去焦点,直到输入被“纠正”。如您所知,只要控件失去焦点,就会触发CancelEventArgs
事件。用户变得“卡住”,因为他们可以“纠正”他们的输入的唯一方法是修改复选框,由于点击单选按钮上的Validating
事件,他们无法访问。
我提出的解决方案是将Validating
事件移至Validated
,而不是单选按钮:
GroupBox
请务必从单选按钮 删除 private void groupBox_Validating(object sender, CancelEventArgs e)
{
if (sender is RadioButton)
{
e.Cancel = !checkBox1.Checked;
}
count++;
//Display the number of times validating is called in the title bar
//Demonstrates when the event is called
Text = count.ToString();
}
事件处理程序。
为清楚起见,我已经以这种方式设置了表格:
现在结果是我无法点击“确定”直到我勾选了复选框。我保留了您的Validating
作业,以便您可以看到表单现在只调用Text = count.ToString()
。
答案 1 :(得分:0)
我最终使用RadioButtons的CheckChanged
和Click
事件。
我跟踪当前有效的RadioButton
并在CheckChanged
事件中进行验证。然后在Click
事件中,如果验证失败,我将恢复之前的活动RadioButton。否则我们可以继续使用RadioButton。
此解决方案适用于组中的两个或多个RadioButton,并且在使用键盘时可以正常工作。
using System.ComponentModel;
using System.Windows.Forms;
namespace ValidateRadioButton
{
public partial class Form1 : Form
{
// RadioButton that is currently active
RadioButton ActiveRadioButton;
bool cancelingChange;
public Form1()
{
InitializeComponent();
activeRadioButton = this.radioButton1;
}
private void radioButton_CheckedChanged(object sender, System.EventArgs e)
{
// Each click fires two events
// One for the RadioButton loosing its check and the other that is gaining it
// We are interested in the one gaining it
if (sender is RadioButton) {
RadioButton radioButton = (RadioButton)sender;
if (radioButton.Checked) {
// If this button is changing because of a canceled check
// do not validate
if (!cancelingChange) {
cancelingChange = !ValidateData();
if (!cancelingChange) {
// Mark this as the active value
activeRadioButton = radioButton;
}
}
}
}
}
private void radioButton_Click(object sender, System.EventArgs e)
{
// This is called after the RadioButton has changed
if (cancelingChange) {
// Check theRadioButton that was previously checked
activeRadioButton.Checked = true;
cancelingChange = false;
}
else {
// Do the thing the RadioButton should do
// If using separate events they all must start with the condition above.
this.Text = ((RadioButton)sender).Name;
}
}
/// <summary>
/// Validate state of data
/// </summary>
/// <returns></returns>
private bool ValidateData()
{
bool result = chkAllowChange.Checked;
if (!result) {
result = MessageBox.Show("Do you want to save your data?", "CheckBox unchecked", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.OK;
if (result) {
// This is where I would save the data
chkAllowChange.Checked = true;
}
}
return result;
}
}
}