简体   繁体   English

将TextBox绑定到ListBox SelectedItem

[英]Binding a TextBox to a ListBox SelectedItem

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 ListBox and some TextBox es. 我有一个类MemberBindingList<Member> membersList ,以及一个ListBox和一些TextBox

The ListBox is bound to membersList . ListBox绑定到membersList

Now I, ideally, want to bind the TextBox es to ListBox.SelectedItem , so that whatever element the user has selected in the ListBox , when they edit a TextBox the element in membersList is updated. 现在,理想情况下,现在我想将TextBox绑定到ListBox.SelectedItem ,以便用户在ListBox选择的任何元素,当他们编辑TextBoxmembersList更新membersList的元素。

I tried just binding the TextBox es 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 . 我尝试仅将TextBox es绑定到ListBox.SelectedItem ,但这使BindingListBox.SelectedItem在绑定创建时所引用的实际元素上,而不是在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 TextBox es in the membersList_SelectedIndexChanged(object sender, EventArgs e) event handler, but this feels very "hacky" and I suspect there is a more standard solution. 我实际上已经通过在membersList_SelectedIndexChanged(object sender, EventArgs e)事件处理程序中清除并重新创建TextBoxBindings而解决了这个问题,但这感觉非常“棘手”,我怀疑还有更标准的解决方案。

Another idea I had was to just make the Binding s 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. 我的另一个想法是将Binding s设置为membersList_SelectedIndexChanged(object sender, EventArgs e)事件处理程序内设置为ListBox.SelectedItemMember temporaryMember ,但随后我必须手动将更改写入到相应的项目中membersList ,这也让我觉得这不是最佳解决方案。

Is there a way to make the Binding dynamic, in the sense that, upon creation, I indicate to it that the DataSource is changing? 有某种方法可以使Binding动态化,即在创建后我向其指示DataSource正在更改?

Or a standard way the change the Binding s DataSource without deleting it and creating a new one? 还是以一种标准的方式更改Binding的DataSource而不删除它并创建一个新的? (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?) (要提及的另一件事:我是C#中的Bindings新手,在搜索解决方案时,我发现显然有两个不同的类,一个在System.Windows.Data命名空间中,另一个在System.Windows.Forms命名空间中。我想我使用的是后者的类,也许我应该使用另一个?

As described in the comments, associating a BindingList (or a DataTable) with a BindingSource can have some interesting benefits. 如注释中所述,将BindingList (或DataTable)与BindingSource关联可以带来一些有趣的好处。

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. BindingList的元素之一被修改或新元素添加到列表中时,所有绑定控件都将自动更新。

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). 您可以使用MovePrevious()MoveNext()MoveFirst()MoveLast()方法来导航BindingList的元素(其他有用的方法和事件可用,请参阅有关BindingSource功能的文档)。

Here, a BindingList<T> (where T is the Member class shown below) is set as the DataSource of a BindingSource. 在这里,将BindingList<T> (其中T是下面显示的Member类)设置为BindingSource的DataSource。 Both are Fields of a Form class, this can be modified as needed. 两者都是Form类的Field,可以根据需要进行修改。
The BindingSource is then used as the DataSource of a ListBox. 然后将BindingSource用作ListBox的数据源。

The Text property of two TextBox controls is then bound, using the BindingSource, to one of the properties of the Member class. 然后,使用BindingSource将两个TextBox控件的Text属性绑定到Member类的属性之一。 This way, the Text property is set to the current Item of the BindingList. 这样,Text属性设置为BindingList的当前Item。 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: 实际上是这样的:

BindingSource和BindingList

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}";
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM