gpt4 book ai didi

c# - 除非您先更改选择,否则 ComboBox 不会更新其显示列表

转载 作者:太空狗 更新时间:2023-10-29 22:08:43 26 4
gpt4 key购买 nike

更新:我在完全测试之前检查了答案它仍然不起作用。我更新了下面的代码,这样您就可以粘贴到一个空的 WinForms 项目中,它应该可以编译。

更新:我发现,如果我将 ComboBox 上的选定项目更改为任何其他项目,它现在会按预期运行(在我下面的代码中,我将从 test1 切换到 test2)。由于我还没有收到任何答案,所以我将问题更改为这个。

为什么我必须在组合框中更改为不同的项目才能显示我对基础数据源所做的更改?

这是正在发生的事情的快速测试用例。

  1. 更改 test1test1asdf txtBroken 中的文本
  2. 单击以提交更改
  3. 组合框中的文本不会更新。
  4. 将组合框更改为 test2
  5. 更改test2test2asdf txtBroken 中的文本
  6. 单击以提交更改
  7. 组合框中的文本立即显示 'test2asdf' 仍然显示 test1对于下拉列表中的第一项
  8. 改为test1
  9. 组合框显示test1文本框显示test1asdf
  10. 将文本框更新为test1asd
  11. 组合框立即显示test1asd

除了在幕后更改加载时选定的项目并将其改回(这看起来像是 hack)之外,我该如何解决这个问题?


我有一个组合框数据绑定(bind)到 BindingSource绑定(bind)到 List<Holder>它有 Holder.Name作为它的显示值。我还有一个绑定(bind)到 Holder.Name 的文本框但如果我更改文本框中的文本,它不会更改组合框中显示的内容。更改所选项目并改回将在文本框中显示更新的文本,但仍会在组合框中显示旧值。如何使组合框中的项目更新?

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;
}
}
}
}

如果我绑定(bind)到 List<String>而不是使用 Holder.Name它按预期工作(这只是一个简单的模型,真正的类不仅仅是一个名称,所以字符串列表将不起作用)。我认为这是错误的线索,但我不知道它是什么。使用 Observable 而不是列表没有区别。

最佳答案

使用 BindingList 而不是 List .它旨在解决此类问题。 .NET 客户端团队的成员 Dinesh Chandnani 在 blog post 中声明以下内容:

BindingList<T> is the new generic implementation of IBindingList which fires ListChanged event when items are added/removed/inserted/etc. from the list. bindingSource hooks on to these events and is thus “aware” of these changes and can notify controls bound thos this BindingSource.

我能够重现您在更新后的条目中描述的问题,但如果不稍微调整代码就无法完全重现原始问题。

通过使用 BindingList<Holder>当焦点离开文本框时,我能够立即得到响应。添加新的数据绑定(bind)时,可以通过使用重载方法来获得即时更新。我还设置了 BindingSourceDataSource直接因为使用 null dataMember在重载的构造函数中没有产生预期的行为。

这是我根据您的示例代码最终得到的代码:

public partial class Form1 : Form
{
private BindingSource bs;
private BindingList<Holder> bList;

public Form1()
{
InitializeComponent();

bList = new BindingList<Holder>();
bList.Add(new Holder("test1"));
bList.Add(new Holder("test2"));

bs = new BindingSource();
bs.DataSource = bList;

cmb.DataSource = bs;
cmb.DisplayMember = "Name";
cmb.ValueMember = "Name";

// updates when focus leaves the textbox
txt.DataBindings.Add("Text", bs, "Name");

// updates when the property changes
//txt.DataBindings.Add("Text", bs, "Name", false, DataSourceUpdateMode.OnPropertyChanged);
}
}

注释掉第一个txt绑定(bind)并取消注释下面的一个以查看 DataSourceUpdateMode.OnPropertyChanged 在行动中。

这里有一些 BindingList资源:

1)替换bsBroken = new BindingSource(lstBroken, null);与:

bsBroken = new BindingSource();
bsBroken.DataSource = lstBroken;

或者在一行中:bsBroken = new BindingSource() { DataSource = lstBroken };

这会产生预期的行为,并立即响应更改(我在上文之前也提到过)。不要使用接受 dataMember 的重载并将其设置为空。这样做会导致您遇到错误行为。

2) 完成上述操作后,我认为不需要 txtBroken_TextChanged事件。注释掉要测试的事件处理程序分配,但您应该能够将其完全删除。

关于c# - 除非您先更改选择,否则 ComboBox 不会更新其显示列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3567897/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com