WPF ComboBox Binding Behavior

I have the following XAML markup:

<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" />

My View DataContext is bound to a view model that contains the public property SelectedCustomer. Customer objects contain a FavoriteProduct property of type Product and Product objects contain the public properties ProductNumber and ProductName.

The behavior I'm looking for is to get SelectedItem ComboBox to update text in TextBox and vice versa. ComboBox for TextBox works fine. Selecting any product in ComboBox updates the TextBox with the product number of this product. However, when I try to go the other way, I get strange behavior. It works only for elements that arrive before the selected element. I will try to explain:

Consider the following list of products ([Product Number], [Product Name]):

  • Fanta li>
  • Pepsi
  • Coca Cola
  • Sprite

, SelectedCustomer Coca Cola ( ). , , TextBox 3, ComboBox Coca Cola. . TextBox 2. ComboBox Pepsi. TextBox - , Coca Cola (3). . 4 (Sprite) 5 (Water) ComboBox Coca Cola. , , , , ItemSource, . 1 (Fanta), . 5 (), . ComboBox? ? , - .

UPDATE:

SelectedProduct SelectedProductNumber. , , , - ComboBox, , updatign . 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");
    }
}
+3
3

, , , .

, , 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" />

, , , , .

MSDN :

IsSynchronizedWithCurrentItem , , " " . WPF, . DataContext , , .

Mode=TwoWay, , , , .

(, , ?)

IsEditable="True" , . , , IsSynchronizedWithCurrentItem="True" IsEditable="True", , .

+1

, ViewModel . , . , viewmodel .

public class MyViewModel:INotifyPropertyChanged
{
    private Product _SelectedProduct;
    public Product SelectedProduct
    {
        get { return _SelectedProduct; }
        set
        {
            _SelectedProduct = value;
            PropertyChanged(this, new PropertyChangedEventArgs("SelectedProduct"));
            _SelectedProductID = _SelectedProduct.ID;
            PropertyChanged(this, new PropertyChangedEventArgs("SelectedProductID"));
        }
    }
    private int _SelectedProductID;
    public int SelectedProductID
    {
        get { return _SelectedProductID; }
        set
        {
            _SelectedProductID = value;
            PropertyChanged(this, new PropertyChangedEventArgs("SelectedProductID")); 
            _SelectedProduct = _AvailableProducts.FirstOrDefault(p => p.ID == value); 
            PropertyChanged(this,new PropertyChangedEventArgs("SelectedProduct"));
        }
    }  
    private IEnumerable<Product> _AvailableProducts = GetAvailableProducts();

    private static IEnumerable<Product> GetAvailableProducts()
    {
        return new List<Product>
                   {
                       new Product{ID=1, ProductName = "Coke"},
                       new Product{ID = 2, ProductName="Sprite"},
                       new Product{ID = 3, ProductName = "Vault"},
                       new Product{ID=4, ProductName = "Barq's"}
                   };
    }

    public IEnumerable<Product> AvailableProducts
    {
        get { return _AvailableProducts; }
    }  
    private Customer _SelectedCustomer; 
    public Customer SelectedCustomer
    {
        get { return _SelectedCustomer; } 
        set
        {
            _SelectedCustomer = value; 
            PropertyChanged(this, new PropertyChangedEventArgs("SelectedCustomer")); 
            SelectedProduct = value.FavoriteProduct;
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

, XAML , viewModel

<TextBox 
  x:Name="MyTextBox" 
  Text="{Binding Path=SelectedProductID, UpdateSourceTrigger=PropertyChanged}" />
<ComboBox 
  x:Name="MyComboBox" 
  ItemsSource="{Binding AvailableProducts}" 
  DisplayMemberPath="ProductName" 
  SelectedItem="{Binding SelectedProduct}" />

INotifyPropertyChanged GetAvailableProducts. . VS, .

+1

Try: SelectedItem = "{Binding Path = YourPath, Mode = TwoWay" } SelectedValue SelectedValuePath.

SelectedValue, Mode = TwoWay, .

- ( , combobox) (, ) , / .

: http://blogs.microsoft.co.il/blogs/tomershamam/archive/2008/03/28/63397.aspx

Note that the main binding is of the form {Binding} or {Binding SourceCollection}, and the data binding is of the form {Binding} or {Binding SourceCollection}.

To get this working, you need to wrap the collection with an object that stores the selected item. WPF has one of these built-in: ObjectDataProvider.

Example: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/068977c9-95a8-4b4a-9d38-b0cc36d06446

0
source

Source: https://habr.com/ru/post/1718641/


All Articles