I would like to have a ComboBox with two options "M" and "F" and set the selection from my code with a string of one of the values. This seems so basic it's embarassing to even ask. However, I haven't seen a single example that doesn't include 50 lines of code with custom classes, etc, etc. To make things even easier, I want to prefill the two option in my XAML. Why is this simple task making me feel like a mental midget? This is what I have:
<ComboBox x:Name="cboGender" >
<ComboBoxItem Tag="M" Content="M"></ComboBoxItem>
<ComboBoxItem Tag="F" Content="F"></ComboBoxItem>
</ComboBox>
Code Behind:
cboGender.SelectedValue = "M";
Please help before I smash my computer and go back to ASP.NET development forever.
Try the following:
cboGender.ItemsSource = new string [] { "M", "F" };
cboGender.SelectedItem = "M";
You need to set the ItemsSource to the collection of items. The ComboBox will then generate the ComboBoxItems for you.
Add the SelectedValuePath and it works:
<ComboBox x:Name="cboGender" SelectedValuePath="Content" >
<ComboBoxItem Tag="M" Content="M"></ComboBoxItem>
<ComboBoxItem Tag="F" Content="F"></ComboBoxItem>
</ComboBox>
(SelectedValuePath="Tag" would work, too, having the same data in two places seems quite redundant either way though)
As a side-note, similar to Colin's answer you can set the items like this:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<ComboBox x:Name="cboGender">
<sys:String>M</sys:String>
<sys:String>F</sys:String>
</ComboBox>
(Both SelectedItem and SelectedValue work in this case)
Try this - cboGender.SelectedIndex = 0; before smashing your system.. :)
To a first approximation, if you ever manipulate WPF UI elements in code you're doing it wrong. Sure, you can create a combo box with an "M" and an "F" and preset its selection:
<ComboBox>
<ComboBoxItem>M</ComboBoxItem>
<ComboBoxItem>F</ComboBoxItem>
<ComboBox.SelectedIndex>0</ComboBox.SelectedIndex>
</ComboBox>
But then what? What do you do with that selection? If your answer involves something like this:
if cboGender.SelectedValue == "M"
you're traveling down a road that will lead you to writing programs that are very hard to maintain.
If, on the other hand, you create a class to bind your UI to, like this:
public class MyViewModel
{
public MyViewModelClass()
{
Gender = "M";
}
public IEnumerable<string> Genders { get { return new string[] { "M", "F" } };
public string Gender { get; set; }
}
Then your XAML - assuming that somewhere along the line you've set the DataContext to an instance of MyViewModel - becomes:
<ComboBox ItemsSource="{Binding Genders}" SelectedValue="{Binding Gender}"/>
Any other logic that uses the Gender property now looks at this class, not the UI. So you can change the UI without affecting your logic, and vice versa.
(Note that while view models typically implement INotifyPropertyChanged, you only need to do this if you're going to be changing the Gender in your code and want the new values to be reflected in the UI.)
Related
when i use this code "var z = comboBox.Items[1].ToString();" and then show z in "MessageBox" i get this message "DataMdellayer.custumer" but i want text of item 1
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" Margin="57,63,0,0" VerticalAlignment="Top" Width="120"/>
and
comboBox.ItemsSource = database.Customers.ToList();
comboBox.DisplayMemberPath = "CustomerSay";
comboBox.SelectedValuePath = "CustomerID ";
You are using CustomerSay property of Customers to show the value.
When you say:
var z = comboBox.Items[1].ToString();
You are converting a Costumer to string
But, considering that you want that costumer's CostumerSay property, you have to look for it.
So you must cast your ComboBoxItem to Costumer
(Customer)comboBox.Items[1]
And then look for the property
var z = ((Customer)comboBox.Items[1]).CustomerSay
1- You can cast your item to the data source object (customer) as #Marko said.
2- Use MVVM and bind your combobox to a ViewModel property. WPF has strong binding system to implement MVVM.
3- You can override ToString method of Customer class:
public class Customer
{
public override string ToString()
{
return CustomerSay;
}
}
I prefer the second solution, but if you don't want to use MVVM pattern #Marko's solution is better.
The index of item one starts at zero in c# so change your code like below to get the item one
var z = comboBox.Items[0].ToString();
I've searched for answers to this for a while, but none seem to match my problem exactly.
I have a window in which I've created a ComboBox. Then in my code, I've created an array:
public string[] myList = new[] { "Item 1", "Item 2" };
Now I want to make those items the options in the ComboBox dropdown. Most of what I found suggests using DataSource and DataBind, but only DataContext is actually available.
I'm sure there's some previous step I'm missing, but I'm still pretty new to this so I'm not sure what it is.
Those answers that you found are for Winforms and you seem to be using WPF. They both have a ComboBox control, but they are actually a completely different controls with different properties. Try this (let's say you call it ComboBox1):
ComboBox1.ItemsSource = myList;
However, you usually need IDs for your items so you can use them when the user selects an item. To do that, you need to bind the ComboBox to a Dictionary instead of a List, like this:
var data = new Dictionary<int, string>{
{100, "Eggplant"},
{102, "Onion"},
{300, "Potato"},
{105, "Tomato"},
{200, "Zuccini"}
};
ComboBox1.ItemsSource = data;
ComboBox1.DisplayMemberPath = "Value";
ComboBox1.SelectedValuePath = "Key";
Now when a user selects "Onion" for example, you will get 102 by using:
int selected = (int)ComboBox1.SelectedValue;
Note: Your ComboBox1 in XAML must have no items, otherwise you will get an error.
If you prefer to keep the items in XAML instead of code-behind, there is no equivalent to the SelectedValuePath property, but you can simulate it using the Tag property like this:
<ComboBox x:Name="ComboBox1" SelectedValuePath="Tag">
<ComboBoxItem Content="Eggplant" Tag="100" />
<ComboBoxItem Content="Onion" Tag="102" />
<ComboBoxItem Content="Potato" Tag="300" />
<ComboBoxItem Content="Tomato" Tag="105" />
<ComboBoxItem Content="Zuccini" Tag="200" />
</ComboBox>
try putting ID's with mapped to each member of the string list. It will work.
Let's say you have one Listbox in WPF with items such as 1,2,3,4,5 etc. How do you make another Listbox, right next to first one, that shows its items according to selection in the first Listbox? So if you select "item 2" in Listbox you'd get 2A, 2B,2C etc in Listbox2, if you select "item 3" you'd get 3A, 3B, 3C etc in Listbox3
Can't embed the picture yet but here's the example of what i need
There is an example of how to implement such cascading ComboBoxes according to the recommended MVVM design pattern available here: https://blog.magnusmontin.net/2013/06/17/cascading-comboboxes-in-wpf-using-mvvm/
You could bind the SelectedItem property of the first ListBox to a source property of your view model. In the setter of this one you then set another collection property that you bind the ItemsSource property of the second ListBox to, e.g.:
<ListBox ItemsSource="{Binding Numbers}" SelectedItem="{Binding SelectedNumber}" />
<ListBox ItemsSource="{Binding SubNumbers}" />
private object _selectedNumber;
public object SelectedNumber
{
get { return _selectedNumber; }
set
{
_selectedNumber = value;
NotifyPropertyChanged();
//set items
SubNumbers = new List<string> { "3A", "3B", "..." };
NotifyPropertyChanged("SubNumbers");
}
}
Make sure that your view model class implements the INotifyPropertyChanged interface and raises change notifications for this to work: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
Alternatively, if your model classes are defined in such a way that each item in the first ListBox has a collection property that returns its related items, you could bind the second ListBox directly to a property of the SelectedItem in the first one:
<ListBox x:Name="lb1" ItemsSource="{Binding Numbers}"/>
<ListBox x:Name="lb2" ItemsSource="{Binding SelectedItem.SubProperty, ElementName=lb1}" />
I am having trouble assigning the a combobox item by using an enum value that the combobox source is assigned to.
The XAML
<ComboBox HorizontalAlignment="Left"
x:Name="cmbName"
VerticalAlignment="Top"
Width="120" Margin="79,48,0,0">
<ComboBox.ItemsSource>
<CompositeCollection>
<ListBoxItem Content="Please Select"/>
<CollectionContainer Collection="{Binding Source={StaticResource Enum}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
The C# that is trying to set the combobox to an item in the enum
// The problem, the assignment doesn't work.
cmbName.SelectedItem = Enum.value;
I can only set a item by using the combobox SelectedIndex
cmbName.SelectedIndex = 2;
But this is hardcoding the index so if the enum changes, so will the value.
So how can I set the combobox by the enum value?
Thanks
It's very hard to tell what your problem is because you haven't fully documented your scenario. As such, all that I can do is to show you how to do what you want. As I prefer to work with properties, I won't be using any Resources for this example, but I'm sure that you'll still be able to relate this solution to your problem.
So, first we have a test enum and some properties and some initialisation:
public enum TestEnum
{
None, One, Two, Three
}
private TestEnum enumInstance = TestEnum.None;
public TestEnum EnumInstance
{
get { return enumInstance; }
set { enumInstance = value; NotifyPropertyChanged("EnumInstance"); }
}
private ObservableCollection<TestEnum> enumCollection = new ObservableCollection<TestEnum>() { TestEnum.None, TestEnum.One, TestEnum.Two, TestEnum.Three };
public ObservableCollection<TestEnum> EnumCollection
{
get { return enumCollection; }
set { enumCollection = value; NotifyPropertyChanged("EnumCollection"); }
}
...
EnumCollection.Add(TestEnum.One);
EnumCollection.Add(TestEnum.Two);
EnumCollection.Add(TestEnum.Three);
EnumInstance = TestEnum.Three;
Then we have a ComboBox:
<ComboBox Name="ComboBox" ItemsSource="{Binding EnumCollection}"
SelectedItem="{Binding EnumInstance}" />
If you run the application, then at this point the selected ComboBoxItem should read Three. Because the ComboBox.SelectedItem is data bound to the EnumInstance property, setting...:
EnumInstance = TestEnum.Two;
... is roughly the same as:
ComboBox.SelectedItem = TestEnum.Two;
Both of these would select the Two value in the ComboBox. However, note this example:
EnumInstance = TestEnum.None;
Setting either the EnumInstance or the ComboBox.SelectedItem property to TestEnum.None would have no effect in the UI because there is no TestEnum.None value in the data bound collection.
I apologise that my answer was descriptive enough, however, the reason why I haven't set my enum as a property as Sheridan has described below is that I need an extra string value in my combo which you can see is "Please Select" and unfortunately, I cannot put this in the enum.
But Sheridan's method and logic is the way to go if you want to do this.
However, for my problem, I simply just used
ComboBox.SelectedValue = Enum.Value.ToString();
Thanks
I'm using WPF and the timer doesn't allow to use int for interval. Instead, it asks for TimeSpan
timer1.Interval = TimeSpan.FromMilliseconds(Convert.ToDouble(comboBox1.SelectedItem));
So I changed my code to this but at runtime it gives me an InvalidCastException, saying that the object cannot be converted from System.Windows.Controls.ComboboxItem to System.IConvertible.
How can I solve this?
You should use this
Convert.ToDouble(comboBox1.SelectedText)
The comboBox1.SelectedItem corresponds to the selected item of the ComboBox control and not with the text of it, which is that you want.
Specifically, the SelectedText property of a CombBox control
Gets or sets the text that is selected in the editable portion of a ComboBox.
as it is stated here.
Update
Please use this one:
((ComboBoxItem)comboBox1.SelectedItem).Content.ToString();
Or in two steps:
ComboBoxItem item = (ComboBoxItem)comboBox1.SelectedItem;
timer1.Interval = TimeSpan.FromMilliseconds(Convert.ToDouble(item.Content.ToString()));
For more information about the ComboBoxItem class, please have a look here.
It appears that you are adding ComboBoxItems directly to your ComboBox.
A cleaner and safer approach than parsing strings would be to continue binding to SelectedItem, but to also bind the ItemsSource to a collection of integers.
Then use the ItemTemplate property of the ComboBox to define how to render the integers if you are not satisfied with the default ToString() rendering.
<ComboBox ItemsSource="{Binding Intervals}" SelectedItem="{SelectedInterval}">
<ComboBox.ItemTemplate>
<DataTemplate TargetType="{x:Type Int64}">
<TextBlock Text="{Binding}" Background="Red"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox>
With properties looking something like this:
public int SelectedInterval {get;set;}
public List<int> Intervals {
get {
var lst = new List<int>();
for(var i = 1000; i <= 10000; i += 500)
{
lst.Add(i);
}
return lst;
}
}
Now you have strongly type properties that you can manipulate without parsing.