Reputation: 180
ive got a simple datagrid made out of comboboxes and textboxes. the last field named "cost" is a textbox,result of the combination of the comboboxes selected. Here's the xaml:
<DataGrid AutoGenerateColumns="False" x:Name="myGrid" ItemsSource="{Binding Path=Routes,UpdateSourceTrigger=PropertyChanged}" >
<DataGrid.Columns>
<DataGridTextColumn Header="Sequenza N°"/>
<DataGridComboBoxColumn Width="100" x:Name="Product"
SelectedValueBinding="{Binding Product, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Product"
DisplayMemberPath="{Binding Product}" >
</DataGridComboBoxColumn>
<DataGridComboBoxColumn Width="100" x:Name="Quality"
SelectedValueBinding="{Binding Quality, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Cestello"
DisplayMemberPath="{Binding Quality}" >
</DataGridComboBoxColumn>
<DataGridTextColumn Binding="{Binding Cost, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Cost"/>
</DataGrid.Columns>
</DataGrid>
And the code behind is a class called Routing which defines a list of values and used propertychanged to change the Cost textbox value.
namespace weblego
{
public partial class Prepare : Window
{
public List<Routing> Routes { get; set; }
public Prepare()
{
InitializeComponent();
Routes = new List<Routing>()
{
new Routing() { Product = "triangolo"}
};
string[] stazioni = { "stazione1", "stazione2", "stazione3" };
string[] qualita = { "low", "medium", "high" };
Product.ItemsSource = stazioni;
Quality.ItemsSource = qualita;
myGrid.ItemsSource = Routes;
}
}
public class Routing : INotifyPropertyChanged
{
private string product;
public string Product
{
get { return product; }
set
{
if (product != value)
{
product = value;
OnPropertyChanged(value);
}
}
}
private string quality;
public string Quality
{
get { return quality; }
set
{
if (quality != value)
{
quality = value;
UpdateCost();
OnPropertyChanged(value);
}
}
}
private double cost;
public double Cost
{
get { return cost; }
set
{
if (cost != value)
{
cost = value;
OnPropertyChanged("Cost");
}
}
}
public void UpdateCost()
{
double qualityMultiple = 1;
switch (Quality)
{
case "high":
qualityMultiple = 1.5;
break;
case "medium":
qualityMultiple = 1;
break;
case "low":
qualityMultiple = 0.5;
break;
}
switch (Product)
{
case "stazione1":
Cost = 10 * qualityMultiple;
break;
case "stazione2":
Cost = 15 * qualityMultiple;
break;
case "stazione3":
Cost = 12.5 * qualityMultiple;
break;
}
}
// Create the OnPropertyChanged method to raise the event
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
everything works fine,but i made a planning error. the last field in the xaml called "Cost" is supposed to be a combobox,not a textbox,and must be filled with values coming from a database. so the XAML should become:
<DataGridComboBoxColumn Width="100" x:Name="Cost"
SelectedValueBinding="{Binding Cost, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Cost"
DisplayMemberPath="{Binding Cost}" />
And the code behind should let me change the itemsource on the Cost element in some way.
private List<string> cost;
public List<string> Cost
{
get { return cost; }
set
{
if (cost != value)
{
cost = value;
OnPropertyChanged("Cost");
}
}
}
public void UpdateCost()
{
if(Quality=="high" && Product == "stazione1")
{
Cost.Add("abc");
Cost.Add("def");
}
}
But when i do this,i get a System.NullReferenceException' saying the Cost is null. How can i change the itemsource of the last combobox depending on the selected values in the other fields of the row?
Upvotes: 0
Views: 79
Reputation: 7004
Okay, You're going to need two things for your combo box to work. First, the list of costs or ItemsSource for your combobox. The next is your actual selectedCost.
Here is a working example:
xaml:
<Window x:Name="window"
x:Class="Sandpit.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:Sandpit"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<DataGrid AutoGenerateColumns="False" x:Name="myGrid" ItemsSource="{Binding Routes}" >
<DataGrid.Columns>
<DataGridTextColumn Header="Sequenza N°" />
<DataGridTemplateColumn Header="Product">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Product}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding AvailableProducts}"
SelectedValue="{Binding Product, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Quality">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Quality}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding AvailableQuality}"
SelectedValue="{Binding Quality, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Quality">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Cost}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding AvailableCosts}"
SelectedValue="{Binding Cost, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
Window code:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace Sandpit
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public ObservableCollection<Routing> routes;
public ObservableCollection<Routing> Routes
{
get
{
return routes;
}
set
{
if (value != routes)
{
routes = value;
NotifyPropertyChanged("Routes");
}
}
}
public MainWindow()
{
Routes = new ObservableCollection<Routing>();
Routes.Add(new Routing { Product = "A", Quality = "C" });
Routes.Add(new Routing { Product = "B", Quality = "D" });
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
And the Route object:
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace Sandpit
{
public class Routing : INotifyPropertyChanged
{
private ObservableCollection<string> availableProducts;
public ObservableCollection<string> AvailableProducts
{
get { return availableProducts; }
set
{
if (availableProducts != value)
{
availableProducts = value;
OnPropertyChanged("AvailableProducts");
}
}
}
private string product;
public string Product
{
get { return product; }
set
{
if (product != value)
{
product = value;
UpdateAvailableCosts();
OnPropertyChanged("Product");
}
}
}
private ObservableCollection<string> availableQuality;
public ObservableCollection<string> AvailableQuality
{
get { return availableQuality; }
set
{
if (availableQuality != value)
{
availableQuality = value;
OnPropertyChanged("AvailableQuality");
}
}
}
private string quality;
public string Quality
{
get { return quality; }
set
{
if (quality != value)
{
quality = value;
UpdateAvailableCosts();
OnPropertyChanged("Quality");
}
}
}
//costs that are available to the user. These get updated when quality etc is changed
private ObservableCollection<string> availableCosts;
public ObservableCollection<string> AvailableCosts
{
get { return availableCosts; }
set
{
if (availableCosts != value)
{
availableCosts = value;
OnPropertyChanged("AvailableCosts");
}
}
}
private string cost;
public string Cost
{
get { return cost; }
set
{
if (cost != value)
{
cost = value;
OnPropertyChanged("Cost");
}
}
}
public void UpdateAvailableCosts()
{
//remove the old available options
AvailableCosts.Clear();
//populate it with just two items made up of the quality and cost for demo
AvailableCosts.Add(Quality + Product);
AvailableCosts.Add(Product + Quality);
//make sure our current cost is in the list by just clearing it
Cost = "";
}
public Routing()
{
AvailableProducts = new ObservableCollection<string> { "A", "B" };
AvailableQuality = new ObservableCollection<string> { "C", "D" };
AvailableCosts = new ObservableCollection<string>();
}
// Create the OnPropertyChanged method to raise the event
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
Produces:
and changing things:
Works perfectly.
Upvotes: 1