Pass ComboBox Selected Item as Method Parameter

2020-05-07 10:16发布

问题:

What's the proper way to pass a ComboBox Selected Item as a Method Parameter?

Or is there even any advantage to doing this?

I have limited experience in program design and passing parameters.


Here's an example method that returns the opposite color of selected.

XAML

<ComboBox x:Name="cboColors" 
          HorizontalAlignment="Left" 
          Margin="179,82,0,0" 
          VerticalAlignment="Top"
          Width="120"
          SelectedIndex="0">
    <System:String>Red</System:String>
    <System:String>Orange</System:String>
    <System:String>Yellow</System:String>
    <System:String>Green</System:String>
    <System:String>Blue</System:String>
    <System:String>Purple</System:String>
</ComboBox>

C Sharp

Hardcoded

ComboBox Selected Item is set in the if statement

// Find Opposite Color
//
public String OppositeColor()
{
    if ((string)cboColors.SelectedItem == "Red")
    {
        return "Green";
    }
    else if ((string)cboColors.SelectedItem == "Orange")
    {
        return "Blue";
    }
    else if ((string)cboColors.SelectedItem == "Yellow")
    {
        return "Purple";
    }
    else if ((string)cboColors.SelectedItem == "Green")
    {
        return "Red";
    }
    else if ((string)cboColors.SelectedItem == "Blue")
    {
        return "Orange";
    }
    else if ((string)cboColors.SelectedItem == "Purple")
    {
        return "Yellow";
    }
    else
    {
        return string.Empty;
    }
}


// Display Opposite Color Button
//
private void button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show(OppositeColor());
}

 

Pass Parameter

ComboBox Selected Item is set to an Object then passed to the Method

// Find Opposite Color
//
public String OppositeColor(Object color)
{
    if (color.Equals("Red"))
    {
        return "Green";
    }

    ...
}


// Display Opposite Color Button
//    
private void button_Click(object sender, RoutedEventArgs e)
{
    // Set Selected Color
    Object color = cboColors.SelectedItem;

    // Display
    MessageBox.Show(OppositeColor(color));
}

回答1:

WPF has bindings that can help you with this. If you create a simple helper class to represent your items in the combobox:

public class ComboItem
{
  public string Color { get; private set; }
  public string OppositeColor { get; private set; }

  public ComboItem(string color, string opposite)
  {
    Color = color;
    OppositeColor = opposite;
  }
}

And in your code behind have a collection the combobox can bind to:

private List<ComboItem> _myComboItems = new List<ComboItem>()
{
  new ComboItem("Red", "Green"),
  new ComboItem("Orange", "Blue"),
  new ComboItem("Yellow", "Purple"),
  new ComboItem("Green", "Red"),
  new ComboItem("Blue", "Orange"),
  new ComboItem("Purple", "Yellow")
};

public List<ComboItem> MyComboItems
{
  get { return _myComboItems; }
}

Implement INotifyPropertyChanged interface to event to the UI when a property in your view changes (without having to implement and dependency properties):

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged(string propertyName)
{
  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

And an item to set when the user makes a selection:

private ComboItem _selected = null;

public ComboItem SelectedComboItem
{ 
  get { return _selected; }
  set
  {
    _selected = value;
    OnPropertyChanged("SelectedComboItem");
  }
}

you are able to set your xaml to look like:

<ComboBox ItemsSource="{Binding MyComboItems}"
          SelectedItem="{Binding SelectedComboItem}"
          DisplayMemberPath="Color"/>

Ince this is in place, when the user presses the button (button1), your handler can do what you want it to in a few different ways:

private void button_Click(object sender, RoutedEventArgs e)
{
  MessageBox.Show(SelectedComboItem.OppositeColor);
}

which accesses the selected items property for opposite color directly, or for your want to pass parameters:

private void button_Click(object sender, RoutedEventArgs e)
{
  MessageBox.Show(GetOppositeColor(SelectedComboItem));
}

private string GetOppositeColor(ComboItem item)
{
  if (item != null)
    return item.OppositeColor;

  return "No opposite color available";
}

To set the initial selected item in the combo:

InitializeComponent();
// some other initialization code here...
SelectedComboItem = MyComboItems[0];

This setting of the property SelectedComboItem will cause the PropertyChanged event to fire (through OnPropertyChanged) which the combobo will get and adjust its selected item.

IMO keeping the types is important for readability and efficiency. Changing an value to type Object then casting back to the specific type it is or using ToString() is less efficient than keeping it as the type it always was to begin with and accessing its value, and it also makes following the code harder when types morph to Object and back again.

My code example eliminates the use of collections for pairing strings together in favor of using a class to wrap the relationship up. This enables you to utilize WPF's magic to get user interaction events (like selecting an item in a combo) and automatically having access to the object the selection represents (through the SelectedItem binding).

Hope this helps.



回答2:

To get the Selected Item's string you need to call ToString(). Then you can pass the string to any method instead of an object. That being said, you can create a Dictionary<string selected,string opposite> to easily get the opposite color using the selected item's name instead of using if/else or switch statements:

private static Dictionary<string, string> _oppositesDictionary = new Dictionary<string, string>()
{
    {"Green", "Red"},
    {"Orange", "Blue"},
    {"Yellow", "Purple"},
    {"Red", "Green"},
    {"Blue", "Orange"},
    {"Purple", "Yellow"}
};

Usage:

public string OppositeColor(string color)
{
    //No need to check if key exists
    return _oppositesDictionary[color];
}



private void button_Click(object sender, RoutedEventArgs e)
{
    string color = cboColors.SelectedItem.ToString();

    MessageBox.Show(OppositeColor(color));
}

Update:

If you want to perform small tasks based on the color name, use a switch statement.

If you want to perform different tasks (no repeating code!) based on the color name, you might want to create a Dictionary<string, Action</* params type*/>> or Dictionary<string, Func</* return type*/, /*params type*/>> if you want to return a value.
Because you have only shown us an example of what you want, I can only think that this is an overkill:

//Methods have to be static when using a field initializer
//Func<string> returns a string and has no paramters
private static Dictionary<string, Func<string>> _colorFunc = new Dictionary<string, Func<string>>()
{
    {"Green", GreenFunc},
    {"Orange", BlueFunc}
    ....
};

private static string GreenFunc()
{
    // green logic
    return "Red";
}

//Usage
public string OppositeColor(string color)
{
    return _colorFunc[color]();
}