Update: I checked the answer before I fully tested it still does not work. I updated the code below so you should just be able to paste in to a empty WinForms project and it should compile.
UPDATE:
I have found that if I change the selected item on the ComboBox to any other item, it now behaves as expected (in my code below I would switch from test1 to test2). As I have not received any answers yet, I change the question to this.
Why do I have to change to a different item in the combo box before it will show the changes I make to the underlying data-source?
Here is a quick test case of what is happening.
- Change
test1
to test1asdf
text in txtBroken
- click off to commit change
- text in combo box does not update.
- Change combo box to test2
- change
test2
to test2asdf
text in txtBroken
- click off to commit change
- text in combo box immediately shows 'test2asdf' still displays
test1
for first item in the drop-down
- change to
test1
- combo box displays
test1
text box displays test1asdf
- update text box to
test1asd
- combo box immediately displays
test1asd
Other than behind the scenes changing the selected item on load and changing it back (this seems like such a hack) how can I fix this?
I have a combo box databound to a BindingSource
bound to a List<Holder>
it has Holder.Name
as its display value. I also have a text box bound to Holder.Name
but if I change the text in the text box it will not change what is displayed in the combo box. Changing selected items and changing back will show the updated text in the text box, but will still have the old value displayed in the combo box. How do I make the item in the combo box update?
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Sandbox_Form
{
public class Form1 : Form
{
public Form1()
{
InitializeComponent();
lstBroken = new BindingList<Holder>();
lstBroken.Add(new Holder("test1"));
lstBroken.Add(new Holder("test2"));
bsBroken = new BindingSource(lstBroken, null);
cmbBroken.DataSource = bsBroken;
cmbBroken.DisplayMember = "Name";
cmbBroken.SelectedIndex = 0;
txtBroken.DataBindings.Add("Text", bsBroken, "Name");
txtBroken.TextChanged += new EventHandler(txtBroken_TextChanged);
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
void txtBroken_TextChanged(object sender, EventArgs e)
{
((Control)sender).FindForm().Validate();
}
private BindingSource bsBroken;
private BindingList<Holder> lstBroken;
private ComboBox cmbBroken;
private TextBox txtBroken;
private Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.cmbBroken = new System.Windows.Forms.ComboBox();
this.txtBroken = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// cmbBroken
//
this.cmbBroken.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbBroken.FormattingEnabled = true;
this.cmbBroken.Location = new System.Drawing.Point(12, 32);
this.cmbBroken.Name = "cmbBroken";
this.cmbBroken.Size = new System.Drawing.Size(94, 21);
this.cmbBroken.TabIndex = 0;
//
// txtBroken
//
this.txtBroken.Location = new System.Drawing.Point(13, 60);
this.txtBroken.Name = "txtBroken";
this.txtBroken.Size = new System.Drawing.Size(93, 20);
this.txtBroken.TabIndex = 1;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(13, 13);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(41, 13);
this.label1.TabIndex = 2;
this.label1.Text = "Broken";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.label1);
this.Controls.Add(this.txtBroken);
this.Controls.Add(this.cmbBroken);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private void cmbWorks_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
public class Holder
{
public Holder(string name)
{
Name = name;
}
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
}
}
}
}
If I bind to a List<String>
instead using Holder.Name
it works as expected (this is just a simple mock-up, the real class has more than just a name so a list of strings will not work). I think this is a clue to what is wrong but I don't know what it is. Using an Observable instead of a list makes no difference.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…