我在业务层中有一些逻辑根据输入限制了ComboBox选项,因此我需要更改底层BindingList中的值。但是当列表发生变化时,双向绑定将成为从UI到实体的单向绑定。
_mComboBox.DataBindings.Add("SelectedValue", _mEntity, "WifeCount");
分配按钮单击处理程序中存在问题的完整代码:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace EnumDataBinding
{
public partial class Form1 : Form
{
ComboBox _mComboBox = new ComboBox();
Button _mCheckButton = new Button();
Button _mAssignButton = new Button();
BindingList<OptionValue> _mBindingList = new BindingList<OptionValue>();
List<OptionValue> _mCacheList = new List<OptionValue>();
Entity _mEntity = new Entity();
public Form1()
{
InitializeComponent();
// create a reset button
_mCheckButton.Size = new Size(100, 30);
_mCheckButton.Text = "Check";
_mCheckButton.Location = new Point(100, 100);
_mCheckButton.Click += new EventHandler(_mCheck_Click);
// create assignment button
_mAssignButton.Size = new Size(100, 30);
_mAssignButton.Text = "Assign";
_mAssignButton.Location = new Point(100, 135);
_mAssignButton.Click += new EventHandler(_mAssignButton_Click);
// create a combo box
_mComboBox = new ComboBox();
_mComboBox.Size = new System.Drawing.Size(300, 30);
_mComboBox.Location = new Point(100, 200);
this.Controls.AddRange(new Control[] {
_mComboBox,
_mCheckButton,
_mAssignButton
});
// fill the bindinglist
_mBindingList.Add(new OptionValue("One", 1M));
_mBindingList.Add(new OptionValue("Two", 2M));
_mBindingList.Add(new OptionValue("Three", 3M));
_mCacheList.Add(new OptionValue("One", 1M));
_mCacheList.Add(new OptionValue("Two", 2M));
_mCacheList.Add(new OptionValue("Three", 3M));
}
void _mAssignButton_Click(object sender, EventArgs e)
{
// reset options
_mBindingList.Clear();
foreach (var o in _mCacheList)
_mBindingList.Add(o);
// EXPECTED: Update ComboBox.SelectedValue and ComboBox.Text
// RESULT: Does not happen.
_mEntity.WifeCount = 3M;
this.Text = string.Format("SelectedValue: {0}; WifeCount: {1}", _mComboBox.SelectedValue, _mEntity.WifeCount);
}
private void PrepareComboBox(ComboBox combobox, BindingList<OptionValue> list)
{
combobox.DropDownStyle = ComboBoxStyle.DropDown;
combobox.AutoCompleteSource = AutoCompleteSource.ListItems;
combobox.AutoCompleteMode = AutoCompleteMode.Suggest;
combobox.DataSource = new BindingSource() { DataSource = list };
combobox.DisplayMember = "Display";
combobox.ValueMember = "Value";
combobox.Text = string.Empty;
combobox.SelectedText = string.Empty;
}
protected override void OnLoad(EventArgs e)
{
// combo box datasource binding
PrepareComboBox(_mComboBox, _mBindingList);
// entity data binding
_mComboBox.DataBindings.Add("SelectedValue", _mEntity, "WifeCount", false);
base.OnLoad(e);
}
void _mCheck_Click(object sender, EventArgs e)
{
this.Text = string.Format("SelectedValue: {0}; WifeCount: {1}", _mComboBox.SelectedValue, _mEntity.WifeCount);
}
}
public class Entity : INotifyPropertyChanged
{
decimal _mWifeCount;
public decimal WifeCount { get { return _mWifeCount; } set { _mWifeCount = value; OnPropertyChanged("WifeCount"); } }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class OptionValue
{
string _mDisplay;
object _mValue;
public string Display { get { return _mDisplay; } set { _mDisplay = value; } }
public object Value { get { return _mValue; } set { _mValue = value; } }
public OptionValue(string display, object value)
{
_mDisplay = display;
_mValue = value;
}
}
}
更新:向ComboBox添加事件处理程序似乎有效:
void _mComboBox_SelectedValueChanged(object sender, EventArgs e)
{
var binding = (sender as Control).DataBindings["SelectedValue"];
if (binding != null)
binding.WriteValue();
this.Text = string.Format("SelectedValue: {0}; WifeCount: {1}", _mComboBox.SelectedValue, _mEntity.WifeCount);
}
答案 0 :(得分:2)
我相信为了进行双向绑定,您需要为绑定列表中的元素实现INotifyPropertyChanged接口。原因是被用作数据源的BindingList不知道任何元素何时发生了变化,除非元素传递了该信息。但是,它仍然可以传递与添加和删除项目相关的事件(假设您将AllowRemove / AllowNew属性指定为true),因为该事件位于列表的范围内,而不是单个元素。
编辑:呸!跳了枪,没有彻底阅读问题/问题。这是问题,添加数据绑定显然默认为单向绑定(仅限初始绑定值)。您需要做的是在将数据绑定添加到组合框时指定DataSourceUpdateMode:
_mComboBox.DataBindings.Add("SelectedValue", _mEntity, "WifeCount", false, DataSourceUpdateMode.OnPropertyChanged);
刚刚测试了这一切,其他一切都保持不变并且有效。让我知道!
编辑:所以它不起作用(我没有清除列表),我想出了原因。所以这就是我注意到的。出于某种原因,只要基础数据源发生变化,实体的绑定上下文就会被清除。不完全确定原因,但我绝对发现这就是问题所在。我发现的方法是在实体的_mComboBox的绑定上下文中添加一个监视:_mComboBox.BindingContext[_mEntity]
并跟踪绑定计数。一旦新项目被添加到_mBindingList,它似乎与ComboBox的内部数据绑定混乱,最终丢弃了Entity.WifeCount的绑定 - &gt;我们设置的ComboBox.SelectedValue绑定。试过各种各样的事情,但我不完全确定为什么PropertyManager在基础数据源发生变化时会删除绑定。
答案 1 :(得分:0)
既然我明白你要做什么,我认为这可能是一个可行的解决方案:
双向绑定很好,但是清除组合框的数据源也会导致数据绑定。如果您要更改绑定列表,则应该在数据源发生更改时重新绑定:
protected override void OnLoad(EventArgs e)
{
// combo box datasource binding
PrepareComboBox(_mComboBox, _mBindingList);
// entity data binding
UpdateBindings();
base.OnLoad(e);
}
public void UpdateBindings()
{
_mComboBox.DataBindings.Clear();
if (_mBindingList.Count != 0) _mComboBox.DataBindings.Add("SelectedValue", _mEntity, "WifeCount");
}
void _mAssignButton_Click(object sender, EventArgs e)
{
_mBindingList.Clear();
foreach (var o in _mCacheList) _mBindingList.Add(o);
// UPDATE BINDINGS HERE - Only do this if changing the binding source
UpdateBindings();
_mEntity.WifeCount = 3M;
this.Text = string.Format("SelectedValue: {0}; WifeCount: {1}", _mComboBox.SelectedValue, _mEntity.WifeCount);
}