简体   繁体   中英

retrieve selected values from datagrid in c#

I've got a datagrid made out of text boxes and comboboxes. So lets say I choose an operation, that operation has a quality range which could be high, low or medium or just two or one of them. The cost must depend on the chosen quality and operation. By calling the someselectionchanged routine I can get the sender and change the list of values for the quality by using intemssource , but thats not enough, because when I change the quality, the cost must be calculated depending on both quality and operation chosen. My idea is that I have to grab either the complete row with values, or the single value selected in the combobox somehow. It is probably a problem related to casting, or in the XAML. I would like to have some direction. Edit. Found the solution thanks to joe. I chnged my code from a list of controls to a full binding,handled by the class itself. inotifypropertychanged along with the propertychanged routine dinamically handle the value changes in the grid. heres the xaml:

<DataGrid AutoGenerateColumns="False" x:Name="myGrid"  ItemsSource="{Binding Path=Routes,UpdateSourceTrigger=PropertyChanged}" >
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Product, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Product name"/>
            <DataGridComboBoxColumn Width="100" x:Name="Operation" 
        SelectedValueBinding="{Binding Operation, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Operation" 
        DisplayMemberPath="{Binding Operation}"  >
            </DataGridComboBoxColumn>
            <DataGridComboBoxColumn Width="100" x:Name="Quality" 
        SelectedValueBinding="{Binding Quality, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Qualità" 
        DisplayMemberPath="{Binding Quality}" />
            <DataGridTextColumn Binding="{Binding Cost, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Cost"/>
        </DataGrid.Columns>
    </DataGrid>

and the code behind:

namespace WpfApplication2
{
public partial class MainWindow : Window
{
    public List<Routing> Routes { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        Routes = new List<Routing>()
            {
            new Routing() { Product = "triangolo"}
              };
        string[] stazioni = { "stazione1", "stazione2", "stazione3" };
        string[] qualita = { "low", "medium", "high" };
        Operation.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);
            }
        }
    }

    // Create the OnPropertyChanged method to raise the event
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    private string operation;
    public string Operation
    {
        get { return operation; }
        set
        {
            if (operation != value)
            {
                operation = value;
                UpdateCost();
                OnPropertyChanged(value);
            }
        }
    }

    private string quality;
    public string Quality
    {
        get { return quality; }
        set
        {
            if (quality != value)
            {
                quality = value;
                UpdateCost();
                OnPropertyChanged(value);
            }
        }
    }

    private double cost;

    public event PropertyChangedEventHandler PropertyChanged;

    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 (Operation)
        {
            case "stazione1":
                Cost = 10 * qualityMultiple;
                break;
            case "stazione2":
                Cost = 15 * qualityMultiple;
                break;
            case "stazione3":
                Cost = 12.5 * qualityMultiple;
                break;
        }

    }
}

}

You could do this by binding something to SelectedItem of the grid which you can access from your code, and perform it like you have been doing.

However, you'll be pulling the logic for calculating cost out of the object which really should be doing this. With WPF you shouldn't need to do all this event tracking at all! You've bound your data to the comboboxes, so they should be getting updated when you make a selection change. (You're already using TwoWay bindin mode).

Your update on Cost should be in the setter of the Operation and Quality properties. If it's here, however those get changed the Cost will always be updated so it's much more robust (you might be doing this kind of change using back-end code at some point in the future). You haven't shown your routing class, but if it's something like this, you shouldn't need any fancy event handling:

class Routes : INotifyPropertyChanged
{
    private string product;
    public string Product
    {
        get { return product; }
        set
        {
            if (product != value)
            {
                product = value;
                OnPropertyChanged("Product");
            }
        }
    }

    private string operation;
    public string Operation
    {
        get { return operation; }
        set
        {
            if (operation != value)
            {
                operation = value;
                UpdateCost();
                OnPropertyChanged("Operation");
            }
        }
    }

    private string quality;
    public string Quality
    {
        get { return quality; }
        set
        {
            if (quality != value)
            {
                quality = value;
                UpdateCost();
                OnPropertyChanged("Quality");
            }
        }
    }

    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 (Operation)
        {
            case "cleaning":
                Cost = 10 * qualityMultiple;
                break;
            case "washing":
                Cost = 15 * qualityMultiple;
                break;
            case "drying":
                Cost = 12.5 * qualityMultiple;
                break;
        }
    }
}

Notice that whenever Operation or Quality are changed, they call a method that updates the Cost. This will be called whenever the binding for these properties sends an update - no events required. So the xaml:

<DataGrid AutoGenerateColumns="False" x:Name="myGrid">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Product, Mode=TwoWay}" Header="Product name"/>
        <DataGridComboBoxColumn Width="100" x:Name="Operation" 
            SelectedValueBinding="{Binding Operation, Mode=TwoWay}" Header="Operation" 
            DisplayMemberPath="{Binding Operation}"  >
        </DataGridComboBoxColumn>
        <DataGridComboBoxColumn Width="100" x:Name="Quality" 
            SelectedValueBinding="{Binding Quality, Mode=TwoWay}" Header="Qualità" 
            DisplayMemberPath="{Binding Quality}" />
        <DataGridTextColumn Binding="{Binding Cost, Mode=TwoWay}" Header="Cost"/>
    </DataGrid.Columns>
</DataGrid>

Edit: Response to further question:

You are not actually firing a change event in your OnPropertyChanged method:

private void OnPropertyChanged(string v)
{
  //  MessageBox.Show(v+" changed");
}

Take a look here: https://msdn.microsoft.com/en-us/library/ms743695(v=vs.100).aspx

This should make everything work:

  // Create the OnPropertyChanged method to raise the event
  protected void OnPropertyChanged(string name)
  {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
          handler(this, new PropertyChangedEventArgs(name));
      }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM