My app: A Store has a Products collection and an int Id property. A Product has string ProductCode and Description properties. A ViewModel references a single instance of Store. ViewModel has a static collection of Products (ProductList). My View's DataContext is set to ViewModel. My View displays Store via the ViewModel.
What works: My View has a TextBlock bound to Store's Id.
What doesn't work: My View has a DataGrid for adding Products to Store's Products collection. The DataGrid for adding Products to Store's Products collection allows me to choose a new ProductCode, using a DataGridComboBoxColumn column. This works fine. However, I want my chosen ProductCode to update the DataGridTextBoxColumn which is bound to a Product's Description.
I've spent hours searching the net and I haven't found anything that quite matches my scenario, except maybe "Example 12" from this link, but I haven't gotten it to work for my project: Best ComboBox Tutorial Ever
Code snippet from my view:
<StackPanel>
<TextBlock Text="{Binding Store.Id}"/>
<DataGrid ItemsSource="{Binding Store.Products}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridComboBoxColumn
Header="ProductCode"
ItemsSource="{x:Static m:ItemsProvider.ProductList}"
SelectedValueBinding="{Binding ProductCode, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="ProductCode"
DisplayMemberPath="ProductCode"/>
<!--
I want Description for my chosen Product to pop in automatically... but how?
-->
<DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
My ViewModel:
public class ViewModel : NotifyObject
{
// Constructor
public ViewModel()
{
_store = new Store() { Id = 1 };
}
// Fields
Store _store;
Product _selectedProduct;
// Properties
public Store Store {
get { return _store; }
set {
_store = value;
base.NotifyPropertyChanged("Commission");
}
}
}
My Product model:
public class Product : NotifyObject
{
// Constructor
public Product() { }
// Fields
string _productCode;
string _description;
// Properties
public string ProductCode {
get { return _productCode; }
set {
_productCode = value;
base.NotifyPropertyChanged("ProductCode");
RefreshDescription(ProductCode);
}
}
public string Description {
get { return _description; }
set {
_description = value;
base.NotifyPropertyChanged("Description");
}
}
// Private Methods
void RefreshDescription(string productCode)
{
if (ItemsProvider.ProductList.Count == 0) {
return;
}
Product product = ItemsProvider.ProductList.FirstOrDefault(p => p.ProductCode == productCode);
this.Description = (product == null ? "" : product.Description);
}
}
My Store model:
public class Store : NotifyObject
{
// Constructor
public Store()
{
Products = new ObservableCollection<Product>();
}
// Fields
int _id;
// Properties
public int Id {
get { return _id; }
set {
_id = value;
base.NotifyPropertyChanged("Id");
}
}
public ObservableCollection<Product> Products { get; set; }
}
My static class for getting a list of products to choose from:
public static class ItemsProvider
{
static ObservableCollection<Product> _productList = new ObservableCollection<Product>();
static ItemsProvider()
{
_productList = new ObservableCollection<Product>() {
new Product() { ProductCode = "111", Description = "a" },
new Product() { ProductCode = "222", Description = "b" },
new Product() { ProductCode = "333", Description = "c" },
new Product() { ProductCode = "444", Description = "d" }
};
}
public static ObservableCollection<Product> ProductList {
get {
return _productList;
}
}
}
From my edited question:
The most significant change to my code is a RefreshDescription method that fires after ProductCode is set for a Product. This method takes ProductCode as an argument and queries a static ProductList to find the first matching Description. The user can change the auto-populated Description property if desired.
Thank you again for those who helped me to come to this conclusion!