正确地将数据绑定到组合框并处理其事件

5
我可以帮助您进行翻译。以下是您需要翻译的内容:

我在 SQL Server 中有一个表,它看起来像这样:

ID Code Name     Surname
1   MS  Mike     Smith 
2   JD  John     Doe
3   UP  Unknown  Person
现在,我想以一种方式将此表中的数据绑定到ComboBox中,使得在ComboBox中显示来自Code列的值。 我是这样进行绑定的:

等等...

在ComboBox中,我将显示来自Code列的值。

我是这样进行绑定的:

SqlDataAdapter sqlAdapter = new SqlDataAdapter("SELECT * FROM dbo.Users ORDER BY Code", MainConnection);
sqlAdapter.Fill(dsUsers, "Users");
cbxUsers.DataSource = dsUsers.Tables["Users"];
cmUsers = (CurrencyManager)cbxUsers.BindingContext[dsUsers.Tables["Users"]];
cbxUsers.DisplayMember = "Code";
这段代码似乎有效。我可以滚动代码列表。此外,我可以手动编写代码,ComboBox会为我自动完成代码。 然而,我想在组合框顶部放置一个标签,以显示当前选定的用户代码的名字和姓氏。 我的思路是:“因此,我需要找到一个事件,在组合框中更改代码后触发该事件,并在该事件中获取当前数据行……” 我正在浏览组合框的事件,尝试了许多事件,但没有成功。 例如:
private void cbxUsers_SelectionChangeCommitted(object sender, EventArgs e)
{
 if (cmUsers != null)
 {
  DataRowView drvCurrentRowView = (DataRowView)cmUsers.Current;
  DataRow drCurrentRow = drvCurrentRowView.Row;
  lblNameSurname.Text = Convert.ToString(drCurrentRow["Name"]) + " " + Convert.ToString(drCurrentRow["Surname"]);
 }
}
这给了我奇怪的结果。首先,当我通过鼠标滚轮滚动时,它没有返回我期望获得的行。例如,在JD上它显示“Mike Smith”,在MS上它显示“John Doe”,在UP上它再次显示“Mike Smith”!另一个问题是,当我开始在ComboBox中输入并按下Enter键时,它不会触发事件。 然而,当我以这种方式将数据绑定到lblNameSurname.Text时,一切都按预期工作:
lblNameSurname.DataBindings.Add("Text", dsusers.Tables["Users"], "Name");
问题在于我只能绑定一个列,但我想要两个。我不想使用两个标签(一个用于显示名字,另一个用于显示姓氏)。 那么,有什么解决办法吗? 此外,我有一个关于ComboBox中数据选择的问题。现在,当我在ComboBox中输入内容时,它允许我输入列表中不存在的字母。 例如,我开始输入“J”,但最后输入了“Jsomerandomtexthere”而不是“JD”。ComboBox会允许这样做,但列表中并没有这样的项目。换句话说,我希望ComboBox阻止用户输入不在代码列表中的代码。
5个回答

2

我自己刚刚进行了一次测试,我认为你可能正在寻找的事件绑定到了错误的事件上(甚至是错误的对象)。

我尝试将事件添加到CurrencyManager对象(cmUsers)的PositionChanged处理程序中,它完全按预期工作。唯一的问题是第一次加载时,它不会触发PositionChanged事件,因此第一个项目永远无法绑定到标签(我相信有更简单的解决方法)。 http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingmanagerbase.positionchanged.aspx

我进行了一个小测试,以查看哪个事件先被触发,似乎是SelectionChangeCommitted事件在PositionChanged事件之前触发,这意味着CurrencyManager尚未更新其内部位置,所以该行代码:

DataRowView drvCurrentRowView = (DataRowView)cmUsers.Current;

选择了错误的数据行。

关于你的第二个问题,大多数控件都不处理按键事件,所以你应该将OnKeyDown或OnKeyPress事件绑定到运行你想要的任何函数(找到与输入对象相关联的索引[即FindString()],并设置ComboBox.SelectedIndex属性为找到的索引,否则会弹出警告)。例如:

if(e.KeyCode == Keys.Enter)
{
    int indx;
    cmbBox.SelectAll();
    if((indx = FindString(cmbBox.SelectedText)) != -1)
        cmbBox.SelectedIndex = indx;
    else
        // Some warning
}

编辑 阅读了您的评论后,我想到了一种更简单的验证方法。在ComboBox的“KeyPress”事件中,使用以下代码:

if(e.KeyChar != (char)Keys.Enter)
{
    if(cmbBox.FindString(cmbBox.Text + e.KeyChar) == -1)
    {
        e.Handled= true;
    }
}

简单易懂。由于我们只限制在列表中的项目,所以不需要处理当用户按下回车键时会自动更改选定的项目(但运行一些验证以确保它是正确的大小写或仅在按下回车键时手动更改SelectedIndex属性也不会有害)。 希望这能帮助到某些人。


感谢您的关注,我会再次查看这个问题。 - Wodzu
你是对的。你让我再次思考了这个问题,我添加了一个bindingSource(它公开了CurrencyManager)事件。通过它们,我已经成功完成了任务。 - Wodzu

0

好的,您可以更改您的SQL以获取名字和姓氏作为一个列,然后一次绑定到该列。另外,我会将组合框和标签放在一个Ajax更新面板中。

关于验证:要在客户端进行验证,您需要事先在客户端具有所有可能的值,或者每次字符后回传并使用SQL进行查询(这可能不是一个好主意 - 可能会使服务器负载过大):

SELECT code FROM TABLE WHERE code LIKE @x + '%' 

自动完成框是一个可接受的选项吗?例如,可以看一下jQuery的自动完成框。


0

谢谢Scott。我认为这些解决方案都不适合我。据我所知,更改DropDownList的样式会禁用键入,而我不想要那样。我只想将键入限制为列表中的内容。但我认为我可以在KeyPress事件中编写自己的验证,这样就没问题了。 - Wodzu

0

请尝试以下方法:

手动创建一个Binding对象以便您有一个对它的引用。使用该Binding对象将其绑定到ComboBox的SelectedItem属性上。这样应该可以获取所选DataRow。将该Binding对象添加到标签(DataBindings collection)中。

处理Binding.Format事件(或者可能是Parse - 无法确定在绑定哪个方向时使用哪个事件),并使用事件参数对象中接收到的DataRow对象来形成包含名字和姓氏的适当名称字符串。您需要将EventArgs的某些其他属性设置为该字符串。

您还可能需要调整一下Binding类的FormattingEnabled属性 - 我已经有一段时间没有做这个了,只是记得这有点棘手。

参见Parse和Format事件的文档:http://msdn.microsoft.com/en-us/library/system.windows.forms.binding_events.aspx


0
通常情况下,当您更改选择并将焦点移出下拉列表时(例如单击外部或按Tab键),下拉列表选定索引更改事件会发生... 如果您需要立即触发它,您应该寻找其他事件或通过JavaScript onchange事件调用事件等...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,