WPF ComboBox 绑定(bind)行为

标签 wpf data-binding combobox

我有以下 XAML 标记:

<TextBox x:Name="MyTextBox" Text="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber, UpdateSourceTrigger=PropertyChanged}" />
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding Products}" DisplayMemberPath="ProductName"
    SelectedValue="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber}"
    SelectedValuePath="ProductNumber" />

我的 View 的 DataContext 绑定(bind)到一个包含名为 SelectedCustomer 的公共(public)属性的 View 模型。 Customer 对象包含 Product 类型的 FavouriteProduct 属性,Product 对象包含公共(public)属性 ProductNumber 和 ProductName。

我正在寻找的行为是让 ComboBox 的 SelectedItem 更新 TextBox 中的 Text,反之亦然。 ComboBox 到 TextBox 工作得很好。选择 ComboBox 中的任何产品会使用该产品的产品编号更新 TextBox。但是,当我尝试走另一条路时,我会出现一些奇怪的行为。它仅适用于所选项目之前的项目。我将尝试解释:

考虑以下产品列表([产品编号]、[产品名称]):

  1. 芬达
  2. 百事可乐
  3. 可口可乐
  4. 雪碧

现在假设 SelectedCustomer 最喜欢的产品是可口可乐(必须是开发人员)。因此,当窗口打开时,TextBox 显示为 3,而 ComboBox 显示为 Coca Cola。迷人的。现在让我们将 TextBox 中的产品编号更改为 2。ComboBox 将其值更新为 Pepsi。现在尝试将 TextBox 中的产品编号更改为高于可口可乐 (3) 的编号。不太可爱。选择 4(雪碧)或 5(水)会使 ComboBox 恢复为可口可乐。因此,行为似乎是您从 ItemSource 中的列表打开窗口宽度的项目下方的任何内容都不起作用。将其设置为 1(芬达),其他都不起作用。将其设置为 5(水),它们都会起作用。这可能与 ComboBox 的一些初始化有关吗?潜在的错误?想知道是否还有其他人看到过这种行为。

更新:

阅读 Mike Brown 的回复后,我为 SelectedProduct 和 SelectedProductNumber 创建了属性。我遇到的问题是,一旦您从 ComboBox 中选择某些内容,您就会陷入无限循环,其中属性会相互更新。我是否错误地实现了 OnPropertyChanged 处理程序,或者我是否遗漏了什么?这是我的 ViewModel 中的一段代码:

private int _SelectedProductNumber = -1;
        public int SelectedProductNumber
        {
            get
            {
                if (_SelectedProductNumber == -1 && SelectedCustomer.Product != null)
                    _SelectedProductNumber = SelectedCustomer.Product.ProductNumber;
                return _SelectedProductNumber;
            }
            set
            {
                _SelectedProductNumber = value;
                OnPropertyChanged("SelectedProductNumber");
                _SelectedProduct = ProductList.FirstOrDefault(s => s.ProductNumber == value);
            }
        }

        private Product _SelectedProduct;
        public Product SelectedProduct
        {
            get
            {
                if (_SelectedProduct == null)
                    _SelectedProduct = SelectedCustomer.Product;
                return _SelectedProduct;
            }
            set
            {
                _SelectedProduct = value;
                OnPropertyChanged("SelectedProduct");
                _SelectedProductNumber = value.ProductNumber;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }

更新 2

我现在通过从两个属性更新 SelectedCustomer.FavouriteProduct 然后在读取它们的值时使用它来稍微更改实现。这现在有效,但我不确定这是“正确的方法”。

private int _SelectedProductNumber = 0;
public int SelectedProductNumber
{
    get
    {
        if (SelectedCustomer.Product != null)
            _SelectedProductNumber = SelectedCustomer.Product.ProductNumber;
        return _SelectedProductNumber;
    }
    set
    {
        _SelectedProductNumber = value;
        SelectedCustomer.FavouriteProduct = ProductList.FirstOrDefault(s => s.ProductNumber == value);
        OnPropertyChanged("SelectedProductNumber");
        OnPropertyChanged("SelectedProduct");
    }
}

private Product _SelectedProduct;
public Product SelectedProduct
{
    get
    {
        if (SelectedCustomer.Product != null)
            _SelectedProduct = SelectedCustomer.Product;
        return _SelectedProduct;
    }
    set
    {
        _SelectedProduct = value;
        SelectedCustomer.FavouriteProduct = value;
        OnPropertyChanged("SelectedProduct");
        OnPropertyChanged("SelectedProductNumber");
    }
}

最佳答案

你的目标不太明确,所以我写了下面的内容,所以支持我能看到的任何一个选项。

要使绑定(bind)到一个项目的两个元素保持同步,您可以在组合框中设置 IsSynchronizedWithCurrentItem="True",如下所示:

<TextBox x:Name="MyTextBox" Text="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber, UpdateSourceTrigger=PropertyChanged}" />
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding Products}" DisplayMemberPath="ProductName"
    SelectedValue="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber}"
    IsSynchronizedWithCurrentItem="True"
    SelectedValuePath="ProductNumber" />

这意味着当前窗口中绑定(bind)到同一背景对象的所有内容都将保持同步,不会出现您所看到的奇怪行为。

此报价形式较长 MSDN article描述效果:

The IsSynchronizedWithCurrentItem attribute is important in that, when the selection changes, that is what changes the "current item" as far as the window is concerned. This tells the WPF engine that this object is going to be used to change the current item. Without this attribute, the current item in the DataContext won't change, and therefore your text boxes will assume that it is still on the first item in the list.

然后按照其他答案的建议设置 Mode=TwoWay 只会确保在您更新文本框时基础对象将被更新以及在您更新对象时文本框被更新。

这使得文本框编辑所选项目的文本,而不是选择组合列表中具有匹配文本的项目(这是您可能正在尝试实现的替代方案?)

要实现同步选择效果,可能值得在组合框上设置 IsEditable="True" 以允许用户在文本框中键入项目并拖放文本框。或者,如果您需要两个框,请将文本框替换为带有 IsSynchronizedWithCurrentItem="True"IsEditable="True" 的第二个组合框,然后将其样式设置为文本框。

关于WPF ComboBox 绑定(bind)行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1483652/

相关文章:

wpf - 如何使用代码更改组合框的边框颜色?

javascript - 为什么 AngularJS 中的双向数据绑定(bind)是一种反模式?

带有数据绑定(bind)的 AndroidX SwipeRefreshLayout

c# - 多个绑定(bind)作为转换器 WPF MVVM 的参数

wpf - 根据数据绑定(bind) ItemsSource 项中的值有条件地更改 WPF ComboBox 项的前景

c# - 为什么在一个 Combo 中更改 SelectedItem 会更改所有其他 Combo?

wpf - WindowsFormsHost ZOrder

c# - 在可编辑组合框中设置闪烁光标的颜色

javascript - 在可编辑网格中,如何使Ext组合框在选择项目时立即结束编辑模式?

带链接的 C# WPF 文本