【问题标题】:Binding a TextBox to a ListBox in Code Behind在后面的代码中将文本框绑定到列表框
【发布时间】:2017-01-01 21:06:30
【问题描述】:

我有一个带有文本框和列表框的主窗口。 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 中选择的任何项目。但是,当我在 Textbox 中键入一些 Text 时,ListBox 中的相应项不会改变。

我在 Google 上搜索了很多关于 UpdateSourceTrigger、绑定等的信息,但几乎所有这些都是关于使用 XAML 的,我发现没有任何东西符合要求。我做错了什么?

【问题讨论】:

  • 你试过在代码后面设置binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;吗?
  • 我有。它没有成功。我认为 Peter 和 unkreativ 的回答解释了为什么不这样做。

标签: c# wpf listbox


【解决方案1】:

这不起作用,因为您正在绑定到一个字符串。所以没有触发 INotifyPropertyChanged 事件,因此列表没有注意到它已更新。尝试使用字符串将列表绑定到某个复杂对象:

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);

【讨论】:

  • 非常感谢。这完全符合我的想法——有一个小缺陷;将对象添加到列表将导致对象的类型显示在列表框本身中,而不是我想要的字符串。幸运的是,这很容易通过添加listBox1.DisplayMemberPath = "MyString"; 来解决
【解决方案2】:

你的问题是你没有告诉你的 UI 字符串已经改变了。您可以使用此接口INotifyPropertyChanged 执行此操作。如果您有兴趣,请查看此answer,并可能进入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 条目。

编辑:更多评论

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多