【问题标题】:The BindingList Datasource of a Combobox refreshes correctly but the Combobox displays items in the wrong order组合框的 BindingList 数据源正确刷新,但组合框以错误的顺序显示项目
【发布时间】:2013-06-05 11:14:46
【问题描述】:

我有一个绑定到ComboBox 控件的BindingList< KeyValuePair < string, string > >。根据某些情况,BindingList 将添加一个新的KeyValuePair。现在,新添加的项目显示在 Combobox 的索引 0 处,而不是末尾。

在调试时,我发现BindingList 的顺序是正确的。 (即附加了新的KeyValuePair

另外,我在ComboBoxSelectedIndexChanged 处理程序中检查了SelectedValue,它似乎不是被选中的ListItem。相反,它是假定的ListItem,如果ComboBox 得到了正确的顺序,就像它的DataSource 一样,-BindingList..

代码是大型项目的一小部分。如果问题不清楚,请告诉我。我可以根据我们的上下文放置代码的相关部分。

这样的事情怎么会发生?我可以做些什么不同的事情?

我有这样的课程。

public class DropdownEntity
{
    //removed all except one members and properties

    private string frontEndName
    public string FrontEndName
    {
        get {return this.frontEndName; }
        set {this.frontEndName= value; }
    }

    //One Constructor
    public DropdownEntity(string _frontEndName)
    {
        this.FrontEndName = _frontEndName;

        //Removed code which initializes several members...
    }

    //All methods removed..

    public override string ToString()
    {
        return frontEndName;
    }
}

在我的 Windows 窗体中,我有一个带有多个选项卡的选项卡控件。在其中一个标签页中,我有一个 DataGridView。用户应该编辑单元格并单击 Next - 按钮。然后,将进行一些处理,并将 TabControl 导航到下一个标签页。

下一个标签页有我提到的问题的组合框。这个页面还有一个返回按钮,它会收回。用户可以再次修改gridview单元格。然后点击下一步按钮。这是订单混乱的时候。

我在这里发布了 Next Button 的 Click 事件处理程序。与该类一起,删除了其余代码。

public partial class AddUpdateWizard : Form
{        
    //Removed all members..

    BindingList<KeyValuePair<string, string>> DropdownsCollection;
    Dictionary<string, DropdownEntity> DropdownsDict;

    //Defined in a partial definition of the class..
    DataGridView SPInsertGridView = new DataGridView();
    ComboBox DropdownsCmbBox = new ComboBox();

    Button NextBtn2 = new Button();
    Button BackBtn3 = new Button();
    //Of course these controls are added to one of the panels

    public AddUpdateWizard(MainForm mainForm)
    {
        InitializeComponent();
        DropdownsDict = new Dictionary<string, DropdownEntity>();
    }

    private void NextBtn2_Click(object sender, EventArgs e)
    {
        string sqlArgName;
        string frontEndName;
        string fieldType;

        for (int i = 0; i < SPInsertGridView.Rows.Count; i++)
        {
            sqlArgName = "";
            frontEndName = "";
            fieldType = "";

            sqlArgName = SPInsertGridView.Rows[i].Cells["InsertArgName"].Value.ToString().Trim();

            if (SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value != null)
            {
                frontEndName = SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value.ToString().Trim();
            }

            if (SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value != null)
            {
                fieldType = SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value.ToString().Trim();
            }

            //I could have used an enum here, but this is better.. for many reasons.
            if (fieldType == "DROPDOWN")
            {
                if (!DropdownsDict.ContainsKey(sqlArgName))
                    DropdownsDict.Add(sqlArgName, new DropdownEntity(frontEndName));
                else
                    DropdownsDict[sqlArgName].FrontEndName = frontEndName;
            }
            else
            {
                if (fieldType == "NONE")
                    nonFieldCount++;

                if (DropdownsDict.ContainsKey(sqlArgName))
                {
                    DropdownsDict.Remove(sqlArgName);
                }
            }

        }

        //DropdownsCollection is a BindingList<KeyValuePair<string, string>>.
        //key in the BindingList KeyValuePair will be that of the dictionary.
        //The value will be from the ToString() function of the object in the Dictionary. 

        DropdownsCollection = new BindingList<KeyValuePair<string,string>>(DropdownsDict.Select(kvp => new KeyValuePair<string, string>(kvp.Key, kvp.Value.ToString())).ToList());

        DropdownsCmbBox.DataSource = DropdownsCollection;

        DropdownsCmbBox.DisplayMember = "Value";
        DropdownsCmbBox.ValueMember = "Key";            

        //Go to the next tab
        hiddenVirtualTabs1.SelectedIndex++;
    }

    private void BackBtn3_Click(object sender, EventArgs e)
    {
        hiddenVirtualTabs1.SelectedIndex--;
    }

    //On Selected Index Changed of the mentioned Combobox..        
    private void DropdownsCmbBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (DropdownsCmbBox.SelectedValue != null)
        {
            if (DropdownsDict.ContainsKey((DropdownsCmbBox.SelectedValue.ToString())))
            {
                var dropdownEntity = DropdownsDict[DropdownsCmbBox.SelectedValue.ToString()];

                DropdownEntityGB.Text = "Populate Dropdowns - " + dropdownEntity.ToString();

                //Rest of the code here..
                //I see that the Datasource of this ComboBox has got the items in the right order.
                // The Combobox's SelectedValue is not that of the selected item. Very Strange behavior!!

            }
        }
    }
}

用户第一次单击“下一步”按钮时,没问题。但是如果他再次单击返回按钮并更改数据网格视图单元格.. 订单将消失。

我知道,看起来可能会令人沮丧。寻求帮助是一件大事。任何帮助将不胜感激!

如果您需要详细说明,请告诉我。

非常感谢:)

【问题讨论】:

  • 请添加您用来重现此内容的代码。
  • 请给我 5 分钟 @Adrian。我将粘贴与此上下文相关的代码部分。
  • 我相信在上面的代码中 DropdownsCollection 应该被定义为 IList 或 BindingList 以便编译......所以你在 DropdownsCollection 中有一个特定的项目顺序,但在 UI 上显示了不同的顺序?这是正确的吗?
  • 抱歉,Adrian,我的意思是键入 BindingList。我手动输入了那部分代码,而不是复制粘贴。 So you have a specific order of the items in DropdownsCollection but on the UI a different order is shown ? Is this correct 你说得对。这正是问题所在。此外,被选中的项目有一个不属于它的值。虽然绑定列表中的所有内容都符合预期。
  • 默认情况下,数据绑定不会改变项目的排序顺序,所以我猜问题出在其他地方,可能在你处理项目的方式上。如果最初该集合包含“A”、“B”和“C”,而您删除“B”并添加“D”,您会期望得到“A”、“C”、“D”的顺序吗?

标签: c# combobox bindinglist


【解决方案1】:

我认为你有两个问题。

首先,如果您想保留项目的顺序,您应该使用OrderedDictionary 而不是常规的。使用 Remove 方法时,普通集合不会保留项目的顺序。您可以查看与 List here 相关的更多信息。

你可以像这样使用这样的字典:

DropDownDict = new OrderedDictionary();
// Add method will work as expected (as you have it now)

// Below you have to cast it before using Select
DropDownCollection = new BindingList<KeyValuePair<string, string>>(DropDownDict.Cast<DictionaryEntry>().Select(kvp => new KeyValuePair<string, string>(kvp.Key.ToString(), kvp.Value.ToString())).ToList());

第二个问题可能是您更改了现有项目的显示名称 (FrontEndName),但保留了密钥。添加新项目时,请尝试删除不再使用的旧项目并添加新项目。

【讨论】:

  • 非常感谢阿德里安,会尝试的。我需要一些时间来检查自己......因为我目前正在处理其他一些模块。
  • 阿德里安,我用的是 OrderedDictionary。我可以理解在我的情况下它可能是一个更好的 DataStructure。谈到您提到的第二个问题。我只更改 OrderedDictionary 的 Value 成员的属性(FrontEndName),用于相同的键。当我调试时,OrderedDictionary 会按预期显示键和值。 bindingList 符合预期。但是组合框仍然显示某些项目被选中,它的 SelectedValue 是其他项目。 :(
  • 我将尝试删除 DictionaryEntry 并再次添加它..,而不是根据其键修改它的值。我仍然不明白为什么会发生这种情况..
  • The second problem could be that you change the display name (FrontEndName) of already existing items, but the key is preserved. When you add a new item, try to remove the old one that you're not using anymore and add a new item. DictionaryEntry 的值(DropdownEntity 对象)中还有很多其他数据。只有属性 FrontEndName 发生了变化。我希望该对象中的其余数据完好无损。这就是我修改的原因,我保留 Dictionary 条目并只修改它的值。
  • 尽管我按键删除了 DictionaryEntry 并添加了一个新的,它带有现有 DropdownEntity 对象的值,但问题仍然存在。最奇怪的是 BindingList 没问题,而 Combobox 项却乱七八糟。
【解决方案2】:

Combobox 的 Sorted 属性设置为 True!直到现在我才检查。我搞砸了。非常抱歉浪费您的时间阿德里安。非常感谢您在这里忍受我的烂摊子.. :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    • 2012-05-15
    • 2013-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多