将 TextBox 绑定到 ListBox SelectedItem [英] Binding a TextBox to a ListBox SelectedItem

查看:34
本文介绍了将 TextBox 绑定到 ListBox SelectedItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试实现一个相对简单的数据管理应用.

我有一个 Member 类和一个 BindingList;membersList,以及一个 ListBox 和一些 TextBoxes.

ListBox 绑定到 membersList.

现在,理想情况下,我想将 TextBoxes 绑定到 ListBox.SelectedItem,以便用户在 ListBox 中选择的任何元素>,当他们编辑 TextBox 时,membersList 中的元素会更新.

我尝试将 TextBoxes 绑定到 ListBox.SelectedItem,但这使 Binding 绑定到 ListBox 的实际元素.SelectedItem 在绑定创建时引用,而不是 ListBox 中选择的任何项目.

firstNameTextBox.DataBindings.Add(new Binding("Text",membersList.SelectedItem, "firstName", false,DataSourceUpdateMode.OnPropertyChanged));

我实际上已经通过在 membersList_SelectedIndexChanged(object sender, EventArgs e) 中清除并重新创建 TextBoxes 的 Bindings 解决了这个问题事件处理程序,但这感觉非常hacky",我怀疑有更标准的解决方案.

我的另一个想法是将 Binding s 设置为 ListBox.SelectedItem 内的 Member promptMember>membersList_SelectedIndexChanged(object sender, EventArgs e) 事件处理程序,但随后我必须手动将更改写入 membersList 中的相应项目,这也让我觉得这不是最优解.

有没有办法使 Binding 动态化,也就是说,在创建时,我会向它表明 DataSource 正在发生变化?

或者改变Binding数据源而不删除它并创建一个新数据源的标准方式?(或者这实际上是最佳实践吗?)

(另一件事要提到:我是 C# 中 Bindings 的新手,在寻找解决方案时,我发现显然有两个不同的类,一个在 System.Windows 中.Data 命名空间和 System.Windows.Forms 命名空间中的另一个.我想我正在使用后者的类.也许我应该使用另一个?)

解决方案

如评论中所述,关联一个

注意,当TextBox的Text被修改时,ListBox的当前Item会实时更新.

BindingList成员 = 空;BindingSource membersSource = null;公共部分类 frmMembers :表单{公共 frmMembers() {初始化组件();初始化数据绑定();}私有无效 InitializeDataBinding(){members = new BindingList();membersSource = new BindingSource(members, null);lstBoxMembers.DataSource = membersSource;txtMemberName.DataBindings.Add(new Binding("Text", membersSource,"FirstName", false, DataSourceUpdateMode.OnPropertyChanged));txtMemberLastName.DataBindings.Add(new Binding("Text", membersSource,"LastName", false, DataSourceUpdateMode.OnPropertyChanged));}private void btnAddMember_Click(object sender, EventArgs e){var frmNew = new frmNewMember();if (frmNew.ShowDialog() == DialogResult.OK && frmNew.newMember != null) {members.Add(frmNew.newMember);}}私有无效 btnMovePrevious_Click(对象发送者,EventArgs e){如果(membersSource.Position > 0){membersSource.MovePrevious();}别的 {membersSource.MoveLast();}}private void btnMoveNext_Click(object sender, EventArgs e){如果(membersSource.Position == membersSource.List.Count - 1){membersSource.MoveFirst();}别的 {membersSource.MoveNext();}}}

<小时>

新会员表格示例:

公共部分类 frmNewMember : 表单{公众会员新会员;private void btnSave_Click(对象发送者,EventArgs e){if (string.IsNullOrEmpty(txtMemberName.Text) ||string.IsNullOrEmpty(txtMemberLastName.Text)) 返回;newMember = new Member(txtMemberName.Text, txtMemberLastName.Text);}}

<小时>

示例成员类:

[Serializable()]公开课成员{公共成员(){}公共成员(字符串名字,字符串姓氏){this.FirstName = firstName;this.LastName = 姓氏;}公共字符串名字{获取;放;}公共字符串姓氏 { 获取;放;}公共覆盖字符串 ToS​​tring() =>$"{this.FirstName} {this.LastName}";}

I am currently trying to implement a relatively simple data management app.

I have a class Member and a BindingList<Member> membersList, as well as a ListBoxand some TextBoxes.

The ListBox is bound to membersList.

Now I, ideally, want to bind the TextBoxes to ListBox.SelectedItem, so that whatever element the user has selected in the ListBox, when they edit a TextBox the element in membersListis updated.

I tried just binding the TextBoxes to ListBox.SelectedItem, but this made the Binding to the actual element that ListBox.SelectedItem is referencing at the moment of the binding creation, not whichever item is selected in the ListBox.

firstNameTextBox.DataBindings.Add(new Binding("Text",
membersList.SelectedItem, "firstName", false,
DataSourceUpdateMode.OnPropertyChanged));

I actually solved this already by just clearing and recreating the Bindings for the TextBoxes in the membersList_SelectedIndexChanged(object sender, EventArgs e) event handler, but this feels very "hacky" and I suspect there is a more standard solution.

Another idea I had was to just make the Bindings to a Member temporaryMember that is set to ListBox.SelectedItem inside the membersList_SelectedIndexChanged(object sender, EventArgs e) event handler, but then I have to manually write the changes through to the corresponding item in membersList which also makes me feel like this isn't the optimal solution.

Is there a way to make the Binding dynamic, in the sense that, upon creation, I indicate to it that the DataSource is changing?

Or a standard way the change the Bindings DataSource without deleting it and creating a new one? (Or is this actually best practice?)

(Another thing to mention: I am new to Bindings in C# and while searching for solutions, I found out that there apparently are two different classes, one in the System.Windows.Data namespace and another in the System.Windows.Forms namespace. I think I am using the class from the latter. Maybe I should use the other one?)

解决方案

As described in the comments, associating a BindingList (or a DataTable) with a BindingSource can have some interesting benefits.

All bound controls are updated automatically when one of the elements of the BindingList is modified or a new element is added to the list.

You can use the MovePrevious(), MoveNext(), MoveFirst(), MoveLast() methods to navigate the elements in the BindingList (other useful methods and events are available, see the Docs about the BindingSource functionality).

Here, a BindingList<T> (where T is the Member class shown below) is set as the DataSource of a BindingSource. Both are Fields of a Form class, this can be modified as needed.
The BindingSource is then used as the DataSource of a ListBox.

The Text property of two TextBox controls is then bound, using the BindingSource, to one of the properties of the Member class. This way, the Text property is set to the current Item of the BindingList. All controls are synchronized:

txtMemberName.DataBindings.Add(new Binding("Text", membersSource, 
    "FirstName", false, DataSourceUpdateMode.OnPropertyChanged));
txtMemberLastName.DataBindings.Add(new Binding("Text", membersSource, 
    "LastName", false, DataSourceUpdateMode.OnPropertyChanged));

This is how it works, in practice:

Note that the current Item of the ListBox is updated in real time when the Text of a TextBox is modified.

BindingList<Member> members = null;
BindingSource membersSource = null;

public partial class frmMembers : Form
{
    public frmMembers() {
        InitializeComponent();
        InitializeDataBinding();
    }

    private void InitializeDataBinding()
    {
        members = new BindingList<Member>();
        membersSource = new BindingSource(members, null);

        lstBoxMembers.DataSource = membersSource;
        txtMemberName.DataBindings.Add(new Binding("Text", membersSource, 
            "FirstName", false, DataSourceUpdateMode.OnPropertyChanged));
        txtMemberLastName.DataBindings.Add(new Binding("Text", membersSource, 
            "LastName", false, DataSourceUpdateMode.OnPropertyChanged));
    }

    private void btnAddMember_Click(object sender, EventArgs e)
    {
        var frmNew = new frmNewMember();
        if (frmNew.ShowDialog() == DialogResult.OK && frmNew.newMember != null) {
            members.Add(frmNew.newMember);
        }
    }

    private void btnMovePrevious_Click(object sender, EventArgs e)
    {
        if (membersSource.Position > 0) {
            membersSource.MovePrevious();
        }
        else {
            membersSource.MoveLast();
        }
    }

    private void btnMoveNext_Click(object sender, EventArgs e)
    {
        if (membersSource.Position == membersSource.List.Count - 1) {
            membersSource.MoveFirst();
        }
        else {
            membersSource.MoveNext();
        }
    }
}


Sample New Member Form:

public partial class frmNewMember : Form
{
    public Member newMember;

    private void btnSave_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(txtMemberName.Text) || 
            string.IsNullOrEmpty(txtMemberLastName.Text)) return;
        newMember = new Member(txtMemberName.Text, txtMemberLastName.Text);
    }
}


Sample Member class:

[Serializable()]
public class Member
{
    public Member() { }
    public Member(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public override string ToString() => $"{this.FirstName} {this.LastName}";
}

这篇关于将 TextBox 绑定到 ListBox SelectedItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆