WPF Listbox binding: SelectedItem not setting - c#

I have a ListBox simplified to the following XAML
<ListBox ItemsSource="{Binding Properties}"
DisplayMemberPath="Name"
SelectedItem="SelectedProperty" />
and in my ViewModel:
private List<Property> propertyList;
private Property selectedProperty;
public List<Property> Properties
{
get
{
return propertyList;
}
set
{
propertyList = value;
NotifyPropertyChanged("Properties");
}
}
public Property SelectedProperty
{
get
{
return selectedProperty;
}
set
{
NotifyPropertyChanged("SelectedProperty");
selectedProperty= value;
}
}
My List box populates fine, but no matter what I try I cannot seem to get the SelectedProperty to update when I select an item in my list box. I have tried switching it all around to use ObservableCollection rather than List and adding an Event handler for CollectionChanged, but this has not worked.
I am sure I am missing something stupid, and cannot see the wood for the trees. I am reaching the end of my tether and need someone to step in and help.

You need to bind to the SelectedProperty:
<ListBox ItemsSource="{Binding Properties}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedProperty}" />

Related

Set default value in a combo box using MVVM

I'm trying to set a default value into a combo box when the application is first loading using the MVVM pattern and it looks like this is all the time unset, combo box being all the time empty when the page loads.
This is my xaml:
<ComboBox Grid.Row="0" Margin="10,0,0,0" Grid.Column="1"
SelectedItem="{Binding Path=JuiceOperations.SelectedItemOption, Mode=TwoWay}"
SelectedIndex="{Binding Path=JuiceOperations.SelectedComboBoxOptionIndex, Mode=TwoWay}"
SelectedValue="{Binding Path=JuiceOperations.SelectedComboBoxOptionIndex, Mode=TwoWay}"
ItemsSource="{Binding Path=JuiceOperations.JuiceOptions}" />
This is the view model code, with its default constructor:
public JuiceViewModel()
{
juiceOperations.SelectedComboBoxOptionIndex = 0;
juiceOperations.SelectedItemOption = "Cola";
}
where I am trying to set the default value of the combo box.
And this is how the properties looks like:
private List<string> juiceOptions = new List<string> { "Cola", "Sprite", "Fanta", "Pepsi" };
private string selectedItemOption = string.Empty;
private int selectedComboBoxOptionIndex = 0;
public int SelectedComboBoxOptionIndex
{
get
{
return this.selectedComboBoxOptionIndex;
}
set
{
this.selectedComboBoxOptionIndex = value;
this.OnPropertyChanged("SelectedComboBoxOptionIndex");
}
}
public List<string> JuiceOptions
{
get
{
return this.juiceOptions;
}
set
{
this.juiceOptions = value;
}
}
public string SelectedItemOption
{
get
{
return this.selectedItemOption;
}
set
{
this.selectedItemOption = value;
this.OnPropertyChanged("SelectedItemOption");
}
}
When selecting an item from combo box the selection is updated into the model and also into the view, so it is working as expected but when the page is first loaded even if the "SelectedComboBoxOptionIndex" and "SelectedItemOption" are being called and their value updated the view of the page is not updated and the empty string is being shown into the combo box where I was expected to see the "Cola" value, instead of the empty string.
Can someone explain me what I am doing wrong and how should I set the default "Cola" value into the combo box ?
Only bind the SelectedItem property of the ComboBox to the SelectedItemOption source property and set the latter to the string "Cola" in the view model. This should work:
<ComboBox Grid.Row="0" Margin="10,0,0,0" Grid.Column="1"
SelectedItem="{Binding Path=JuiceOperations.SelectedItemOption}"
ItemsSource="{Binding Path=JuiceOperations.JuiceOptions}" />
public JuiceViewModel()
{
juiceOperations.SelectedItemOption = "Cola";
}
Don't mix SelectedItem, SelectedIndex and SelectedValue. You only need one.
mm8 above absolutely right, that should fix your issue.
On a side note, what you have there will work for a static selection list, but consider using an ObservableCollection<string> instead of a List<string>. The former implements INotifyCollectionChanged, which allows the view to be notified if there has been a change in the collection. When you bind an Observable Collection to the view, the view automatically subscribes to the CollectionChanged event. You will need this if you ever need to add or remove options at run time. Side note, OnCollectionChanged will not fire if you simply modify an item, for that you would still need to callOnPropertyChanged("JuiceOptions") in the setter.
something like this (with the appropriate private backing field):
public ObservableCollection<string> JuiceOptions
{
get
{
return this.juiceOptions;
}
set
{
this.juiceOptions = value;
this.OnPropertyChanged("JuiceOptions");
}
}
The value of juiceOperations.SelectedItemOption, that is, "Cola", is not the same "Cola" stored in the ItemsSource. You would need to do something like juiceOperations.SelectedItemOption = juiceOperations.JuiceOptions.First().

Binding to ObservableCollection works, but not ListCollectionView

I'm trying to get my ListCollectionView to bind to a combo box. However, it seems to only work when I bind to my ObservableCollection.
Properties:
private ListCollectionView sitesView;
public ListCollectionView SitesView
{
get { return sitesView; }
set
{
sitesView = value;
RaisePropertyChanged(() => SitesView);
}
}
public ObservableCollection<ISite> SitesCollection { get; set; }
Constructor:
SitesCollection = new ObservableCollection<ISite>();
SitesView = (ListCollectionView)CollectionViewSource.GetDefaultView(SitesCollection);
When binding like so:
<ComboBox Grid.Row="2" ItemsSource="{Binding SitesView, Mode=TwoWay}"/>
any item I add to SitesCollection does not get shown when I click the drop down in my combo box. But if I do the binding like so:
<ComboBox Grid.Row="2" ItemsSource="{Binding SitesCollection, Mode=TwoWay}"/>
it works fine and I see the items when I click the drop down.
Attempts at fixing: After I add the an item to the SitesCollection, I tried to raise property change notifications on both the ListCollectionView and the ObservableCollection and it didn't make a difference. Any ideas?
I didn't have time to test my answer; I apologize and will follow up.
I think your issue is because CollectionViewSource.GetDefaultView(...)
returns an ICollectionView, which I believe is essentially just a wrapper that enables the underlying data to be sorted.
Try setting SitesView to the SourceCollection of the DefaultView.
SitesView = (ListCollectionView)CollectionViewSource.GetDefaultView(SitesCollection).SourceCollection

Alternatives for bind an event to a property

I've a list box but if I click on an item, I must see the details of that item. I've made this code where I try to bind the SelectionChanged event to a property whit type RelayCommand and mode is two way.
<ListBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"
SelectedItem="{Binding SelectedVillage, Mode=TwoWay}"
ItemContainerStyle="{StaticResource lstidflt}"
SelectionChanged="{Binding SelectedVillageChanged, Mode=TwoWay}"
ItemTemplate="{StaticResource weatheritemdt}"
ItemsSource="{Binding VillageList}" />
This doesn't work of course because you can't bind an event to a property or a property to a method and vice versa. You can only bind a property to a property. So the question is now are there alternatives to bind a SelectionChanged event to a property?
I use C# in a Windows universal 10 application with the MVVM light architecture.
You could just let the binding of the SelectedItem property
<ListBox ItemsSource="{Binding VillageList}" SelectedItem="{Binding SelectedVillage, Mode=TwoWay}" />
And do the job in the setter
public class VillageViewModel
{
public ObservableCollection<Village> VillageList { get; set; }
private Village selectedItem;
public Village SelectedItem
{
get { return selectedItem; }
set
{
if (selectedItem == value)
return;
selectedItem = value;
// Do logic on selection change.
}
}
}
What I do (in WPF) is bind the selected item to a full property then raise the event in the set part. It will look something like this;
private Village _SelectedVillage;
public Village SelectedVillage{
get {return _SelectedVillage;}
set {
_SelectedVillage = value;
RaiseEvent myEvent();
}
}
You can also raise the relaycommand or check for a trigger in xaml. If you go with the property, look at dependency property if it's available in win 10 universal.

WPF XAML Binding List and Combobox

I am teaching myself how to bind classes to XAML objects. I can't find anything on data within lists. Either that or I don't know the terminology very well. I want to make a combobox that is tied to the list, displaying the name of each Item in the Items list. How would I bind this to the combobox?
class Section
{
List<Item> Items = new List<Item>();
}
class Item
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
Try This,
<ComboBox ItemsSource="{Binding Items}" DisplayMemberPath="Name" />
Make your Items collection as a property.
public List<Item> Items { get; set;}
Section Class should be public and make it as your DataContext
Assuming Section is the current DataContext :
<ComboBox ItemsSource="{Binding Items}"
DisplayMemberPath="Name" />

MVVM Pattern in Master-Detail when editing details

i have a ObservableCollection with some data. They are displayed as Master (ListBox) and Detail (some Labels). I use binding and IsSynchronizedWithCurrentItem to show the correct details to the selected master item. This works all fine. Now i want to edit some details (load different image). I implemeted this a a Button Command in the ViewModel.
But how do i know which item is selected (UI) in the ViewModel-layer ?
Thanks for help
I don't really find the IsSynchronizedWithCurrentItem property that useful in MVVM scenarios.
Just expose another SelectedItem property in the ViewModel.
public ItemType SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
// your logic here
}
}
You need to bind a value or Enumerable of values of your ViewModel to the ListBox's SelectedItems property.
SelectedItems="{Binding VMProperty}"
http://msdn.microsoft.com/en-us/library/system.windows.controls.listbox.selecteditems(v=vs.110).aspx
If you only want one item selected you need to set:
SelectionMode="Single"
SelectedItem="{Binding VMProperty}"
If I understood you right, what you are looking for is the following
<ListBox SelectedItem="{Binding ObjectName, UpdateSourceTrigger=PropertyChanged}"/>
Plus under your ViewModel you have to declare the following
public YourObject ObjectName { get; set; }
Simple as that!
The normal way to detect which item in the collection is currently selected in the UI is to data bind a property of the same type as the items in the collection to the ListBox.SelectedItem property:
<ListBox ItemsSource="{Binding SomeCollection}"
SelectedItem="{Binding SomeProperty}" />
Now, whenever the user selects a new item, the SomeProperty setter will be called:
public YourDataType SomeProperty
{
get { return someProperty; }
set
{
someProperty = value;
// The value has just changed
}
}

Categories