当 BindingList 中的现有项目发生更改时,Listbox 拒绝更新

Posted

技术标签:

【中文标题】当 BindingList 中的现有项目发生更改时,Listbox 拒绝更新【英文标题】:Listbox refuses to update when changes occur in existing items in a BindingList 【发布时间】:2011-08-06 16:32:41 【问题描述】:

一天中的大部分时间我都在发疯,试图让它发挥作用。

我的代码中有几个类。我会尽量把相关代码贴在下面,尽量简短

public class ServerSettings

    private BindingList<Server> serverList = new BindingList<Server>();

    public ServerSettings()
    

    

    private void readSettings()
               
        string list = "/Settings/Server";
        XmlNodeList Xn = settings.SelectNodes(list);

        foreach (XmlNode xNode in Xn)
        
            Server tmpSrv = new Server();
            for (int i=0; i<xNode.ChildNodes.Count; i++)
            
                if(xNode.ChildNodes[i].Name == "Name")
                    tmpSrv.Name = xNode.ChildNodes[i].InnerText;
                else if(xNode.ChildNodes[i].Name == "Host")
                    tmpSrv.Host = xNode.ChildNodes[i].InnerText;
                else if(xNode.ChildNodes[i].Name == "Username")
                    tmpSrv.Username = xNode.ChildNodes[i].InnerText;
                else if(xNode.ChildNodes[i].Name == "Password")
                    tmpSrv.Password = xNode.ChildNodes[i].InnerText;
            
            tmpSrv.ID = xNode.Attributes["ID"].Value;
            serverList.Add(tmpSrv);
        
    

    public BindingList<Server> getServerList()
    
        return serverList;
    

    public void setServer(Server srv, bool isNew)
    
        if(isNew)
        
            serverList.Add(srv);
            srvCount++;
        
        else
        
            string list = "/Settings/Server[@ID='"+srv.ID+"']";
            XmlNodeList Xn = settings.SelectNodes(list);
            if(Xn.Count == 1)
            
                XmlNode srvNode = Xn[0];
                for (int i=0; i<srvNode.ChildNodes.Count; i++)
                
                    if(srvNode.ChildNodes[i].Name == "Name")
                        srvNode.ChildNodes[i].InnerText = srv.Name;
                    else if(srvNode.ChildNodes[i].Name == "Host")
                        srvNode.ChildNodes[i].InnerText = srv.Host;
                    else if(srvNode.ChildNodes[i].Name == "Username")
                        srvNode.ChildNodes[i].InnerText = srv.Username;
                    else if(srvNode.ChildNodes[i].Name == "Password")
                        srvNode.ChildNodes[i].InnerText = srv.Password;
                
            
        

    

在另一个表单类中,我有以下函数,该函数在程序启动时被调用一次

public void populateServerListBox(ref BindingList<Server> srvList)
    
        this.serverListBox.DisplayMember = "Name";
        this.serverListBox.DataSource = srvList;
    

最后

public partial class NewServerForm : Form

    private bool _isEdit = false;
    private bool isCanceled = true;
    private Server selSrv = null;

    public NewServerForm()
    
        InitializeComponent();
    

    void NewServerFormOKBtClick(object sender, EventArgs e)
    
        isCanceled = false;
        this.Close();
    

    void NewServerFormCancelBtClick(object sender, EventArgs e)
    
        isCanceled = true;
        this.Close();
    

    public bool isEdit
    
        get
        
            return _isEdit;
        
        set
        
            _isEdit = value;
        
    

    public void showForm(ref Server srv)
    
        selSrv = srv;
        isEdit = true;
        this.newServerFormNameTb.Text = selSrv.Name;
        this.newServerFormHostTb.Text = selSrv.Host;
        this.newServerFormUsernameTb.Text = selSrv.Username;
        this.newServerFormPwdTb.Text = selSrv.Password;
        this.ShowDialog();
    

    public void showForm()
    
        selSrv = new Server();
        this.ShowDialog();
    


    void NewServerFormFormClosing(object sender, FormClosingEventArgs e)
               
        if(isCanceled || selSrv == null)
            this.Dispose();
        else if(isEdit && selSrv != null)
        
            selSrv.Name = this.newServerFormNameTb.Text;
            selSrv.Host = this.newServerFormHostTb.Text;
            selSrv.Username = this.newServerFormUsernameTb.Text;
            selSrv.Password = this.newServerFormPwdTb.Text;
            selSrv.BgwConfigPath = this.newServerFormBgwlocTb.Text;
            isCanceled = true;
            MainProgram.serverSettings.setServer(selSrv, false);
            this.Dispose();
        
        else if(selSrv != null)
        
            selSrv.Name = this.newServerFormNameTb.Text;
            selSrv.Host = this.newServerFormHostTb.Text;
            selSrv.Username = this.newServerFormUsernameTb.Text;
            selSrv.Password = this.newServerFormPwdTb.Text;

            MainProgram.serverSettings.setServer(selSrv, true);
            isCanceled = true;
            this.Dispose();
        
    

我正在尝试为不同的服务器构建一个简单的用户设置菜单,用户可以在其中添加、删除或更改现有的服务器设置。在带有列表框的表单中,用户单击一个按钮,该按钮会弹出另一个带有一些文本框的表单供用户填写,然后单击“确定”以执行更改。

这些更改反映在 bindingList 中的项目中(新项目或对现有项目的更新)。添加新的服务器项或从 bindingList 中删除一项会立即反映在列表框中,但是对现有项进行更改会拒绝更新列表框。关闭包含列表框的表单并再次打开它将显示更改,但在列表框中完成更改后我无法立即使其工作。

我尝试在列表框上调用 refresh(),在 BindingList 上调用 resetBindings() 以及其他一些方法。

我错过了什么吗?

【问题讨论】:

【参考方案1】:

列表框的一个脏修复和已知的Microsoft错误:如果您需要刷新框内容set datasource = null,然后重新绑定它。

它不更新的原因是列表中的对象没有改变,它只检查对象的引用而不是它们的内容。

[编辑]

正确的做法是在“服务器”类上实现INotifyPropertyChanged 接口。让我给你一些参考资料。

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=VS.80).aspx

http://www.gavaghan.org/blog/2007/07/17/use-inotifypropertychanged-with-bindinglist/

http://www.codeproject.com/KB/cs/BindBetterINotifyProperty.aspx

how to update listbox items with INotifyPropertyChanged

【讨论】:

谢谢,问题解决了。我的典型运气,我的第一个程序,我已经遇到了错误。我还有一个问题,如何避免从 newServerForm 调用 MainProgram.serverSettings.setServer?我宁愿不必像这样走来走去并以适当的方式去做。

以上是关于当 BindingList 中的现有项目发生更改时,Listbox 拒绝更新的主要内容,如果未能解决你的问题,请参考以下文章

如何从BindingList中删除哪些项目[重复]

为啥 Bindinglist 在数据库更改后不更新?

如果主程序中的值发生更改,如何更改 gui 上项目的颜色

C# 中 datagridview 绑定BindingList类型和更新

当项目中发生更改时,Xcode 如何编译文件?

C#:将更改从 DataGridView 推送到 BindingList 回数据库?