在后台代码中将文本框绑定到列表框

本文关键字:绑定 列表 文本 后台 代码 | 更新日期: 2023-09-27 18:04:00

我有一个主窗口与文本框和列表框。TextBox是双向绑定到ListBox的,ListBox是由BindingList填充的。

InitializeComponent();
productNames = new BindingList<string>(/*some content*/);
Binding binding = new Binding();
binding.Mode = BindingMode.TwoWay;
binding.Path = new PropertyPath("SelectedItem");
binding.ElementName = "listBox1";
textBox1.SetBinding(TextBox.TextProperty, binding);
listBox1.ItemsSource = productNames;

到目前为止,一切顺利:ListBox很好地显示了列表的内容,TextBox忠实地显示了在ListBox中选择的任何项。但是,当我在文本框中输入一些文本时,列表框中相应的项不会改变。

我在谷歌上搜索了很多关于UpdateSourceTrigger、binding等的内容,但几乎所有内容都是关于使用XAML的,我没有找到符合要求的内容。我做错了什么?

在后台代码中将文本框绑定到列表框

这不起作用,因为您绑定的是字符串。所以没有INotifyPropertyChanged-events被触发,所以列表没有注意到它被更新了。尝试用字符串将列表绑定到一些复杂的对象:

class CompexObject : INotifyPropertyChanged
{
    private string myString;
    public event PropertyChangedEventHandler PropertyChanged;
    public string MyString
    {
        get { return this.myString; }
        set
        {
            this.myString = value;
            this.PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(MyString)));
        }
    }
}

然后将列表设置为:

 productNames = new BindingList<ComplexObject>(/*some content*/);

你的绑定应该改为:

Binding binding = new Binding();
binding.Mode = BindingMode.TwoWay;
binding.Path = new PropertyPath("SelectedItem.MyString");
binding.ElementName = "listBox1";
textBox1.SetBinding(TextBox.TextProperty, binding);

你的问题是你没有告诉你的UI字符串已经改变了。你可以用这个接口INotifyPropertyChanged来做。如果你感兴趣的话,看看这个答案,也许你会进入MVVM

但是对于后面代码的简单解决方案,我建议在XAML中使用依赖属性和绑定,就像这个例子一样。

XAML:

<Window x:Class="Test.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Test"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525"
    Name="myWindow">
<StackPanel>
    <ListBox ItemsSource="{Binding ElementName=myWindow, Path=ItemCollection, Mode=OneWay}"
             SelectedItem="{Binding ElementName=myWindow, Path=SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

    </ListBox>

    <TextBox Text="{Binding ElementName=myWindow, Path=TextBoxText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>

背后的代码:

namespace Test
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// Store your ListBox entrys here
        /// </summary>
        public ObservableCollection<string> ItemCollection
        {
            get { return (ObservableCollection<string>)GetValue(ItemCollectionProperty); }
            set { SetValue(ItemCollectionProperty, value); }
        }
        // Using a DependencyProperty as the backing store for ItemCollection.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemCollectionProperty =
            DependencyProperty.Register("ItemCollection", typeof(ObservableCollection<string>), typeof(MainWindow), new PropertyMetadata(new ObservableCollection<string>()));

        /// <summary>
        /// This binds to the TextBox text
        /// </summary>
        public string TextBoxText
        {
            get { return (string)GetValue(TextBoxTextProperty); }
            set { SetValue(TextBoxTextProperty, value); }
        }
        // Using a DependencyProperty as the backing store for TextBoxText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextBoxTextProperty =
            DependencyProperty.Register("TextBoxText", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty, OnTextBoxTextChanged));
        private static void OnTextBoxTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            MainWindow self = d as MainWindow;
            if(self != null)
            {
                self.OnTextBoxTextChanged(args.NewValue.ToString());
            }
        }
        private void OnTextBoxTextChanged(string newValue)
        {
            if (this.ItemCollection.Contains(newValue))
            {
                this.SelectedItem = newValue;
            }
            else
            {
                this.SelectedItem = null;
            }
        }

        /// <summary>
        /// This binds to the selected item of your ListBox
        /// </summary>
        public string SelectedItem
        {
            get { return (string)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }
        // Using a DependencyProperty as the backing store for SelectedItem.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty, OnSelectedItemChanged));
        private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            MainWindow self = d as MainWindow;
            if (self != null)
            {
                self.OnSelectedItemChanged(args.NewValue as string);
            }
        }
        private void OnSelectedItemChanged(string newValue)
        {
            if (!this.TextBoxText.Equals(newValue) && !string.IsNullOrEmpty(newValue))
            {
                this.TextBoxText = newValue;
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            this.ItemCollection.Add("Name 1");
            this.ItemCollection.Add("Name 2");
            this.ItemCollection.Add("Name 3");
            this.ItemCollection.Add("Name 4");
            this.ItemCollection.Add("Name 5");
        }
    }
}

TextBox文本与ListBox的"ItemsSource"中的项目不匹配时,它也取消选择ListBox条目。

编辑:更多评论