问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/36603993/adding-items-to-a-combobox-in-the-datagrid