DataSource 中的更新重置了 CheckedListBox 复选框
Updates in the DataSource reset CheckedListBox checkboxes
我有一个 CheckedListBox,绑定到一个 BindingList:
private BindingList<string> list = new BindingList<string>();
public MyForm()
{
InitializeComponent();
list.Add("A");
list.Add("B");
list.Add("C");
list.Add("D");
checkedListBox.DataSource = collection;
}
单击某个按钮时,列表会更新:
private void Button_Click(object sender, EventArgs e)
{
list.Insert(0, "Hello!");
}
它工作正常,CheckedListBox 已更新。但是,当某些项目被选中时,单击按钮不仅会更新列表,还会将所有项目重置为未选中状态。我该如何解决?
谢谢!
您需要自己跟踪检查状态。
作为一种选择,您可以为包含文本和检查状态的项目创建模型 class。然后在 ItemCheck
event of the control, set check state value of the item model. Also in ListChenged
event of your BindingList<T>
刷新项目的检查状态。
例子
创建 CheckedListBoxItem
class:
public class CheckedListBoxItem
{
public CheckedListBoxItem(string text)
{
Text = text;
}
public string Text { get; set; }
public CheckState CheckState { get; set; }
public override string ToString()
{
return Text;
}
}
像这样设置 CheckedListBox
:
private BindingList<CheckedListBoxItem> list = new BindingList<CheckedListBoxItem>();
private void Form1_Load(object sender, EventArgs e)
{
list.Add(new CheckedListBoxItem("A"));
list.Add(new CheckedListBoxItem("B"));
list.Add(new CheckedListBoxItem("C"));
list.Add(new CheckedListBoxItem("D"));
checkedListBox1.DataSource = list;
checkedListBox1.ItemCheck += CheckedListBox1_ItemCheck;
list.ListChanged += List_ListChanged;
}
private void CheckedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
((CheckedListBoxItem)checkedListBox1.Items[e.Index]).CheckState = e.NewValue;
}
private void List_ListChanged(object sender, ListChangedEventArgs e)
{
for (var i = 0; i < checkedListBox1.Items.Count; i++)
{
checkedListBox1.SetItemCheckState(i,
((CheckedListBoxItem)checkedListBox1.Items[i]).CheckState);
}
}
另一种方法。它不需要自定义 class 的支持(尽量不要)。
由于基础项目列表在本例中是非托管(在别处管理),因此必须手动处理项目的检查状态.
查看在 BindingList
中添加或删除项目时引发的事件顺序是什么可能很有趣(例如,在更新列表之前没有通知列表更改的事件,ListChangedEventArgs.OldIndex
永远不会设置,因此总是 -1
,等等)。
由于CheckedListBox的来源是一个简单的List<string>
,更新列表时,Item的CheckState
丢失了。因此,需要存储这些状态并在需要时重新应用,调用 SetItemCheckedState 方法。
由于必须调整项目的状态以匹配新的列表组成(在删除或插入项目之后)并且此过程是同步的,ItemCheck
事件(用于更新所有项目CheckState
) 被异常提出并需要延迟执行。这就是这里使用 BeginInvoke()
的原因。
总而言之,一个专门的 class 对象在内部存储这些状态,如 所示,是可行的方法。在这里,绑定受到基础 classes 中缺乏支持的困扰。并不是说它在任何地方都另有说明:例如,CheckedListBox.DataSource
甚至不可浏览。
private BindingList<string> clbItemsList = new BindingList<string>();
public MyForm()
{
InitializeComponent();
clbItemsList.Add("A");
// (...)
checkedListBox1.DataSource = clbItemsList;
clbItemsList.ListChanged += this.clbListChanged;
checkedListBox1.ItemCheck += (s, e) => { BeginInvoke(new Action(()=> CheckedStateCurrent())); };
}
private void clbListChanged(object sender, ListChangedEventArgs e)
{
foreach (var item in clbCheckedItems.ToArray()) {
if (e.ListChangedType == ListChangedType.ItemAdded) {
checkedListBox1.SetItemCheckState(item.Index >= e.NewIndex ? item.Index + 1 : item.Index, item.State);
}
if (e.ListChangedType == ListChangedType.ItemDeleted) {
if (item.Index == e.NewIndex) {
clbCheckedItems.Remove(item);
continue;
}
checkedListBox1.SetItemCheckState(item.Index > e.NewIndex ? item.Index - 1 : item.Index, item.State);
}
}
}
private List<(CheckState State, int Index)> clbCheckedItems = new List<(CheckState State, int Index)>();
private void CheckedStateCurrent()
{
clbCheckedItems = checkedListBox1.CheckedIndices.OfType<int>()
.Select(item => (checkedListBox1.GetItemCheckState(item), item)).ToList();
}
我有一个 CheckedListBox,绑定到一个 BindingList:
private BindingList<string> list = new BindingList<string>();
public MyForm()
{
InitializeComponent();
list.Add("A");
list.Add("B");
list.Add("C");
list.Add("D");
checkedListBox.DataSource = collection;
}
单击某个按钮时,列表会更新:
private void Button_Click(object sender, EventArgs e)
{
list.Insert(0, "Hello!");
}
它工作正常,CheckedListBox 已更新。但是,当某些项目被选中时,单击按钮不仅会更新列表,还会将所有项目重置为未选中状态。我该如何解决?
谢谢!
您需要自己跟踪检查状态。
作为一种选择,您可以为包含文本和检查状态的项目创建模型 class。然后在 ItemCheck
event of the control, set check state value of the item model. Also in ListChenged
event of your BindingList<T>
刷新项目的检查状态。
例子
创建 CheckedListBoxItem
class:
public class CheckedListBoxItem
{
public CheckedListBoxItem(string text)
{
Text = text;
}
public string Text { get; set; }
public CheckState CheckState { get; set; }
public override string ToString()
{
return Text;
}
}
像这样设置 CheckedListBox
:
private BindingList<CheckedListBoxItem> list = new BindingList<CheckedListBoxItem>();
private void Form1_Load(object sender, EventArgs e)
{
list.Add(new CheckedListBoxItem("A"));
list.Add(new CheckedListBoxItem("B"));
list.Add(new CheckedListBoxItem("C"));
list.Add(new CheckedListBoxItem("D"));
checkedListBox1.DataSource = list;
checkedListBox1.ItemCheck += CheckedListBox1_ItemCheck;
list.ListChanged += List_ListChanged;
}
private void CheckedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
((CheckedListBoxItem)checkedListBox1.Items[e.Index]).CheckState = e.NewValue;
}
private void List_ListChanged(object sender, ListChangedEventArgs e)
{
for (var i = 0; i < checkedListBox1.Items.Count; i++)
{
checkedListBox1.SetItemCheckState(i,
((CheckedListBoxItem)checkedListBox1.Items[i]).CheckState);
}
}
另一种方法。它不需要自定义 class 的支持(尽量不要)。
由于基础项目列表在本例中是非托管(在别处管理),因此必须手动处理项目的检查状态.
查看在 BindingList
中添加或删除项目时引发的事件顺序是什么可能很有趣(例如,在更新列表之前没有通知列表更改的事件,ListChangedEventArgs.OldIndex
永远不会设置,因此总是 -1
,等等)。
由于CheckedListBox的来源是一个简单的List<string>
,更新列表时,Item的CheckState
丢失了。因此,需要存储这些状态并在需要时重新应用,调用 SetItemCheckedState 方法。
由于必须调整项目的状态以匹配新的列表组成(在删除或插入项目之后)并且此过程是同步的,ItemCheck
事件(用于更新所有项目CheckState
) 被异常提出并需要延迟执行。这就是这里使用 BeginInvoke()
的原因。
总而言之,一个专门的 class 对象在内部存储这些状态,如 CheckedListBox.DataSource
甚至不可浏览。
private BindingList<string> clbItemsList = new BindingList<string>();
public MyForm()
{
InitializeComponent();
clbItemsList.Add("A");
// (...)
checkedListBox1.DataSource = clbItemsList;
clbItemsList.ListChanged += this.clbListChanged;
checkedListBox1.ItemCheck += (s, e) => { BeginInvoke(new Action(()=> CheckedStateCurrent())); };
}
private void clbListChanged(object sender, ListChangedEventArgs e)
{
foreach (var item in clbCheckedItems.ToArray()) {
if (e.ListChangedType == ListChangedType.ItemAdded) {
checkedListBox1.SetItemCheckState(item.Index >= e.NewIndex ? item.Index + 1 : item.Index, item.State);
}
if (e.ListChangedType == ListChangedType.ItemDeleted) {
if (item.Index == e.NewIndex) {
clbCheckedItems.Remove(item);
continue;
}
checkedListBox1.SetItemCheckState(item.Index > e.NewIndex ? item.Index - 1 : item.Index, item.State);
}
}
}
private List<(CheckState State, int Index)> clbCheckedItems = new List<(CheckState State, int Index)>();
private void CheckedStateCurrent()
{
clbCheckedItems = checkedListBox1.CheckedIndices.OfType<int>()
.Select(item => (checkedListBox1.GetItemCheckState(item), item)).ToList();
}