【问题标题】:How to manage ListBox/CheckedListBox bound with List<> in WinForms?如何在 WinForms 中管理 List<> 绑定的 ListBox/CheckedListBox?
【发布时间】:2014-08-29 22:00:09
【问题描述】:

如何将ListBoxCheckedListBox 与程序员定义对象的List&lt;&gt; 绑定?绑定后如何编辑数据?我可以通过哪个对象修改数据?如何在数据更改时更新列表框视图?当用户点击CheckedListBox时,如何检索项目复选框的选中状态?

我想分享我所拥有的一些知识,因为我看到了很多关于这个主题的线程,但没有一个能清楚地展示如何处理数据绑定。不要误解我的尝试,我只是想展示一种轻松的方法。

欢迎评论。希望对您有所帮助!

【问题讨论】:

  • 根据问答风格编辑。

标签: c# winforms list data-binding listbox


【解决方案1】:

在下文中,“ListBox”不同于“listbox”,后者是用于ListBoxCheckedListBox 的通用术语。


首先,绑定在testForm_Load 事件处理程序中完成。必须说明要绑定哪个对象以及要在列表框中显示什么属性/字段。

((ListBox)m_checkedListBox).DataSource = m_underList;
((ListBox)m_checkedListBox).DisplayMember = "PropToDisplay";

据我了解,绑定列表框的行为类似于只读单向(数据源 => 列表框)镜像视图。我们只能通过处理底层数据对象或控件的事件机制来影响列表框并检索其数据(忘记Items&co。)。

对于CheckListBox,我们可以通过在ItemCheck事件中添加ItemCheckEventHandler方法来检索选中的项目,然后将其存储到程序员定义的属性/字段的对象中。

m_checkedListBox.ItemCheck += new ItemCheckEventHandler(this.ItemCheck);

但我们无法定义数据源(基础列表)中内部检查项的状态以在CheckListBox 中显示为已检查。 CheckListBox 似乎不是为这种行为而设计的。

然后,可以通过底层列表随意添加或删除Userclass 对象或调用您想要的任何方法。只是不关心列表框。

m_underList.Add(new UserClass("Another example", 0, true));

最后,列表框的视图刷新。我看到很多文章都在谈论将 DataSource 设置为 null 然后将其重新分配回之前的对象。我寻找一种更好的方法来做到这一点(更好还是更漂亮?)。下面的方法很简单。

void refreshView(ListBox lb, object dataSource);

参考资料:

有关从列表框中检索用户选择的补充信息,请访问MSDN ListControl Class Examples

以下是CheckedListBox 被绑定、填充数据和清除的简单示例的完整代码。请注意,为了简单起见,我从列表框和数据列表都排序的原则开始。


UserClass.cs:用于存储显示/检查状态/隐藏数据的类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestForm
{
    class UserClass
    {
        private int m_underProp;

        // ctors
        public UserClass(string prop2Disp, int anotherObj, bool isChecked = false)
        {
            PropToDisplay = prop2Disp;
            IsChecked = isChecked;
            AnotherProp = anotherObj;
        }

        public UserClass()
        {
            PropToDisplay = string.Empty;
            IsChecked = false;
            AnotherProp = 0;
        }

        //  Property to be displayed in the listbox
        public string PropToDisplay
        {
            get;
            set;
        }

        //  For CheckedListBox only!
        //  Property used to store the check state of a listbox
        //  item when a user select it by clicking on his checkbox
        public bool IsChecked
        {
            get;
            set;
        }

        //  Anything you want
        public int AnotherProp
        {
            get
            {
                return m_underProp;
            }

            set
            {
                m_underProp = value;
                //  todo, processing...
            }
        }

        //  For monitoring
        public string ShowVarState()
        {
            StringBuilder str = new StringBuilder();

            str.AppendFormat("- PropToDisplay: {0}", PropToDisplay);
            str.AppendLine();
            str.AppendFormat("- IsChecked: {0}", IsChecked);
            str.AppendLine();
            str.AppendFormat("- AnotherProp: {0}", AnotherProp.ToString());

            return str.ToString();
        }
    }
}

TestForm.Designer.cs:表单的设计

namespace TestForm
{
    partial class testForm
    {
        /// <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.m_checkedListBox = new System.Windows.Forms.CheckedListBox();
            this.m_toggle = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // m_checkedListBox
            // 
            this.m_checkedListBox.CheckOnClick = true;
            this.m_checkedListBox.FormattingEnabled = true;
            this.m_checkedListBox.Location = new System.Drawing.Point(13, 13);
            this.m_checkedListBox.Name = "m_checkedListBox";
            this.m_checkedListBox.Size = new System.Drawing.Size(171, 109);
            this.m_checkedListBox.TabIndex = 0;
            // 
            // m_toggle
            // 
            this.m_toggle.Location = new System.Drawing.Point(190, 53);
            this.m_toggle.Name = "m_toggle";
            this.m_toggle.Size = new System.Drawing.Size(75, 23);
            this.m_toggle.TabIndex = 1;
            this.m_toggle.Text = "Fill";
            this.m_toggle.UseVisualStyleBackColor = true;
            this.m_toggle.Click += new System.EventHandler(this.m_toggle_Click);
            // 
            // testForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(275, 135);
            this.Controls.Add(this.m_toggle);
            this.Controls.Add(this.m_checkedListBox);
            this.Name = "testForm";
            this.Text = "Form";
            this.Load += new System.EventHandler(this.testForm_Load);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.CheckedListBox m_checkedListBox;
        private System.Windows.Forms.Button m_toggle;
    }
}

TestForm.cs:表单的行为

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;

namespace TestForm
{
    public partial class testForm : Form
    {
        //  a List which will contain our external data. Named as the underlying list
        private List<UserClass> m_underList;

        public testForm()
        {
            InitializeComponent();

            m_underList = new List<UserClass> (3);
        }

        private void testForm_Load(object sender, EventArgs e)
        {
            //  Bind the CheckedListBox with the List
            //  The DataSource property is hidden so cast the object back to ListBox
            ((ListBox)m_checkedListBox).DataSource = m_underList;

            //  Tell which property/field to display in the CheckedListBox
            //  The DisplayMember property is hidden so cast the object back to ListBox
            ((ListBox)m_checkedListBox).DisplayMember = "PropToDisplay";

            /*
             * The CheckedListBox is now in "read-only" mode, that means you can't add/remove/edit
             * items from the listbox itself or edit the check states. You can't access
             * the underlying list through the listbox. Considers it as a unidirectionnal mirror
             * of the underlying list. The internal check state is disabled too, however
             * the ItemCheck event is still raised...
             */

            //  Manually set the ItemCheck event to set user defined objects
            m_checkedListBox.ItemCheck += new ItemCheckEventHandler(this.ItemCheck);
        }

        private void ItemCheck(object sender, ItemCheckEventArgs evnt)
        {
            if (sender == m_checkedListBox)
            {
                if (!m_checkedListBox.Sorted)
                {
                    //  Set internal object's flag to remember the checkbox state
                    m_underList[evnt.Index].IsChecked = (evnt.NewValue != CheckState.Unchecked);

                    //  Monitoring
                    Debug.WriteLine(m_underList[evnt.Index].ShowVarState());
                }
                else
                {
                    //  If sorted... DIY
                }
            }
        }

        private void m_toggle_Click(object sender, EventArgs e)
        {
            if (sender == m_toggle)
            {
                if (m_toggle.Text == "Fill")
                {
                    //  Fill the checkedListBox with some data
                    //  Populate the list with external data.
                    m_underList.Add(new UserClass("See? It works!", 42));
                    m_underList.Add(new UserClass("Another example", 0, true));
                    m_underList.Add(new UserClass("...", -7));
                    m_toggle.Text = "Clear";
                }
                else
                {
                    //  Empty the checkedListBox
                    m_underList.Clear();
                    m_toggle.Text = "Fill";
                }

                //  Refresh view
                //  Remember CheckedListBox inherit from ListBox
                refreshView(m_checkedListBox, m_underList);
            }
        }

        //  Magic piece of code which refresh the listbox view
        void refreshView(ListBox lb, object dataSource)
        {
            CurrencyManager cm = (CurrencyManager)lb.BindingContext[dataSource];
            cm.Refresh();
        }
    }
}

这是表单的视图。第一个图像是加载时的表单,第二个是单击“填充”按钮时的图像。可能会注意到,尽管IsChecked 属性在添加到数据源时设置为 true,但未选中列表框中的第二项。

【讨论】:

  • One may note that the second item in the listbox is not checked despite the IsChecked property set to true。所以它不起作用?
  • 在数据列表中设置对象的IsChecked属性不会影响镜像项复选框的勾选状态,是的。
猜你喜欢
  • 2011-02-10
  • 2016-04-18
  • 2011-10-19
  • 2015-09-01
  • 2012-06-15
  • 2010-12-03
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多