The question may be dumb but I am a newbie in WPF, so I am sorry. I found a lot of similar questions here, but none of them helped.
I have a form that gets some object with a Location
property as input.
I want this Location
property to be selected in the ComboBox
when the form is shown.
I also want to make this property changeable during the lifecycle of the form.
I madea binding in this way:
<ComboBox Name="CB_Location" ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}" DisplayMemberPath="LocationName" SelectedValuePath="LocationID" SelectionChanged="CB_Location_SelectionChanged"/>
public class Location
{
public int LocationID { get; set; }
public string LocationName { get; set; }
}
public Form(object _obj)
{
InitializeComponent();
lctrl = new LocationController();
Locations = lctrl.GetAllLocations();
SelectedLocation = lctrl.GetLocationById(_obj.LocationID);
DataContext = this;
}
public List<Location> Locations { get; set; }
public Location SelectedLocation; { get; set; }
The ComboBox
is populated with objects correctly, but I cannot set the SelectedItem
property correctly.
The issue why the selected item is not set is because SelectedLocation
is a field, which you cannot bind. For more information about binding sources, you can refer to the documentation.
You can bind to public properties, sub-properties, as well as indexers, of any common language runtime (CLR) object. The binding engine uses CLR reflection to get the values of the properties. Alternatively, objects that implement ICustomTypeDescriptor or have a registered TypeDescriptionProvider also work with the binding engine.
In order to make your current code work, just make SelectedLocation
a public property.
public Location SelectedLocation { get; set; }
Apart from that, if you only want to bind the selected item, setting a SelectedValuePath
is useless.
<ComboBox Name="CB_Location"
ItemsSource="{Binding Locations}"
SelectedItem="{Binding SelectedLocation}"
DisplayMemberPath="LocationName"
SelectionChanged="CB_Location_SelectionChanged"/>
If you wanted to bind the SelectedValue
where the SelectedValuePath
is applicable instead, you would have to expose a property that matches the type of the selected value path, here int
.
public int SelectedLocationID { get; set; }
Then you can bind this the SelectedValue
with value path LocationID
(without SelectedItem
).
<ComboBox Name="CB_Location"
ItemsSource="{Binding Locations}"
DisplayMemberPath="LocationName"
SelectedValuePath="LocationID"
SelectedValue="{Binding SelectedLocationID}"
SelectionChanged="CB_Location_SelectionChanged"/>
Another note on updating properties. It seems that you do not implement the INotifyPropertyChanged
interface. If you set Location
for instance, the user interface (here the ComboBox
) will not reflect the change, as it does not get notified. Therefore, if you intend to change the Location
or other properties bound in your form, you have to implement INotifyPropertyChanged
, e.g.:
public class YourViewModel : INotifyPropertyChanged
{
private Location _selectedLocation;
public Location SelectedLocation
{
get => _selectedLocation;
set
{
if (_selectedLocation == value)
return;
_selectedLocation = value;
OnPropertyChanged();
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// ...other code.
}