MVVM: Binding to ListBox.SelectedItem isn't being updated? - wpf

How do I bind a view model property to the ListBox.SelectedItem property?
I have created a simple MVVM demo to try to figure this one out. My view model has these properties:
private ObservableCollection<DisneyCharacter> p_DisneyCharacters;
public ObservableCollection<DisneyCharacter> DisneyCharacters
{
get { return p_DisneyCharacters; }
set
{
p_DisneyCharacters = value;
base.FirePropertyChangedEvent("DisneyCharacters");
}
}
private DisneyCharacter p_SelectedItem;
public DisneyCharacter SelectedItem
{
get { return p_SelectedItem; }
set
{
p_SelectedItem = value;
base.FirePropertyChangedEvent("SelectedItem");
}
}
I want to bind the SelectedItem property to the item selected in the list box. Here is the XAML for the list box:
<ListBox ItemTemplate="{StaticResource MasterTemplate}"
ItemsSource="{Binding Path=DisneyCharacters}"
SelectedItem="{Binding Path=Selectedtem, Mode=TwoWay}"
HorizontalAlignment="Stretch" />
Here is my problem: The view model SelectedItem property isn't being updated when I change the selection in the list box.
I did a test where I temporarily replaced the view model SelectedItem property with a SelectedIndex property, and I bound that to the ListBox.SelectedIndex property. That property updated fine--it's just the SelectedItem property that I can't get to work.
So, how do I fix the SelectedItem binding? Thanks for your help.

Well, there it is, big as life. In the XAML I was binding to a view model property called:
Selectedtem
^^
Unfortunately, the actual name is SelectedItem. So this code actually works--I solved the problem early this afternoon and then spent the rest of the afternoon and all evening scouring the web, before I noticed the spelling error.
My wife told me at 3:00 this afternoon, "You know, it's going to turn out to be something small." And so it did--a missing letter I. Well, at least I can go to bed now.

Related

WPF MVVM ListBox/ComboBox ItemsSource won't update UI from ViewModel

i have a container such as a listbox, combobox etc that its ItemsSource property is bound to an observable collection in my view model.
When i'm trying to add/remove items from the collection via some method in my VM it won't reflect in the UI,
The only way the UI would actually refresh is if i assign the collection a new value (i.e another collection with the relevant data) which forces him to re-bind the whole collection.
maybe i'm missing/don't understand something about the collection binding issue, either way if someone has a solution/good explanation/both it would be great.
here is a sample from my View(in this case its a listbox)
<ListBox
Grid.Row="9"
Grid.Column="1"
Grid.ColumnSpan="3"
Width="200"
Height="200"
ItemsSource="{Binding PreSavedRecordingScheduleList,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedPreSavedRecordingSchedule,UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Display"/>
and here is my ViewModel:
private ObservableCollection<ScheduledRecordingObject> m_PreSavedRecordingScheduleList;
PreSavedRecordingScheduleList = new ObservableCollection<ScheduledRecordingObject>();
public ObservableCollection<ScheduledRecordingObject> PreSavedRecordingScheduleList
{
get
{
return m_PreSavedRecordingScheduleList;
}
set
{
m_PreSavedRecordingScheduleList = value;
OnPropertyChanged("PreSavedRecordingScheduleList");
}
}
ScheduledRecordingObject also implements INotifyPropertyChanged.
viewmodel
public ObservableCollection<yourType> MyItemsSource {get;set}
initialize once in contructor and use clear, add and remove to alter it
view
<ListBox ItemsSource="{Binding MyItemsSource}"/>
just be sure that the right DataContext is set.
thats how it should look in your code
EDIT:
some hints to your posted code:
//remove the UpdateSourceTrigger=PropertyChanged - makes no sense the Mode is OneWay anyway :)
ItemsSource="{Binding PreSavedRecordingScheduleList}"
//the following line should just called once and at best in ctor
//but the binding will of course work too when you assign a new collection
PreSavedRecordingScheduleList = new ObservableCollection<ScheduledRecordingObject>();
all in all your code looks good, and if the viewmodel is the Datacontext of your Listbox then it should work. let me know what Snoop is showing :)
Remove the OnPropertyChanged("PreSavedRecordingScheduleList"); from the ObservableCollection. Actually you don't need a backing field. Attach the CollectionChanged event on the ObservableCollection, something like this
1- Inside the ViewModel constructor attach the event CollectionChanged
PreSavedRecordingScheduleList = new ObservableCollection<ScheduledRecordingObject>();
PreSavedRecordingScheduleList.CollectionChanged += PreSavedRecordingScheduleList_CollectionChanged;
2- Inject the OnPropertyChanged("PreSavedRecordingScheduleList") in the event handler
void PreSavedRecordingScheduleList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged("PreSavedRecordingScheduleList");
}

MVVM Light and combobox

I am new to WPF and MVVM Light, I would appreciate if you could help me :-)
I would like to know how to implement a combobox with MVVM Light to do the following:
1) Select an item in the combobox
2) Based on the value selected, change other text fields in the GUI.
Thank you for your help.
Romain
Well:
View:
<ComboBox ItemsSource="{Binding SourceData}" SelectedItem="{Binding SelectedSourceData,Mode=TwoWay}"/>
<TextBlock Text="{Binding SelectedDataInTextFormat}"/>
ViewModel:
public class ViewModel:ViewModelBase
{
public ObservableCollection<Foo> SourceData{get;set;}
public Foo SelectedSourceData
{
get{return _selectedFoo;}
set{_selectedFoo=value;
RaisePropertyChanged("SelectedSourceData");
SelectedDataInTextFormat=Foo.ToString();
}
public string SelectedDataInTextFormat
{
get{return _selectedDataInTextFormat;}
set{_selectedDataInTextFormat=value;
RaisePropertyChanged("SelectedDataInTextFormat");
}
}
Basically, to ensure that your view model is able to receive the updated selected item from the combobox make sure the SelectedItem binding is set to Mode=TwoWay. To ensure that you're pushing data from the viewmodel to the view when a change occuers in the viewmodel make sure you call the RaisePropertyChanged helper class for the property you want updated in the view.

How to know that property was changed from View

My silverlight project uses MVVM.For examlpe, I have textbox, that binded to ViewModel property. Textbox content can change from View or ViewModel. I need know when content changed from View. How can I implement this accordingly MVVM?
If your viewmodel has INotifyPropertyChanged/INotifyPropertyChanging implemented then you can hook into it. That works for me.
if you use bindings, you get the information in your setter.
Here is a little example:
XAML:
<TextBox Text="{Binding MyProperty, Mode=TwoWay}" />
C# of your ViewModel:
private string myProperty = "Test";
public String MyProperty
{
get { return myProperty; }
set
{
Debug.WriteLine("Property set");
myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
Each time, you change the text and the TextBox looses the focus, the setter get called.
If you want to get the setter called each time you hit a key, have a look here. This is a little bit of a quick and dirty solution for triggering the binding ;) A better way would be to write an Behaviour for this.
Hope this helps!
BR,
TJ

WPF User Control Binding Issue?

I have this:
public MyView: UserControl
{
public IList<Person> PersonList { get; set; }
public MyView()
{
//code
}
public void Display(MyData myData)
{
DataContext=myData;
}
//code
}
The XAML for this includes a ComboBox :
ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=PersonList}"
For some reason this does not work and the combo box does not get populated ( however, If I use the code-behind and I say comboBox.ItemsSource = PersonList then the combo box does got populated ).
Any ideas ?
Regards,
MadSeb
Your property is set to private, and are you sure that you are setting the DataContext.
* EDIT *
Based on the change you made above, you're setting your datacontext incorrectly. Your "PersonList" is anIList<> on your MyView class, but you're setting your data context to something else.
Try adding items to PersonList within MyView and setting this.DataContext = this; Also, as suggested, switch your IList<> to an ObservableCollection<>.
I would also highly suggest reading up on the Model View ViewModel (MVVM) approach. It will help out a lot. Josh Smith has a lot of good articles about the MVVM approach (and has written a good book about it too).
Here's a link to his blog. His book is linked there, as well.
I suspect it's because you're not firing any property-changed events. If you don't notify your UI when the property's value is first set, the binding won't update. Look into the INotifyPropertyChanged interface and implement it in your class.
Similarly, if your IList property isn't an ObservableCollection or doesn't implement INotifyCollectionChanged, then when you add items to the list the databound UI won't reflect this.
I believe your binding statement is the problem.
"{Binding RelativeSource={RelativeSource Self}, Path=PersonList}" is looking for a "PersonList" on the combobox itself.
Are you seeing any binding errors in the output window?
Ideally you'd want to bind to a property in your DataContext (MyData)

Using MVVM how can I find out if a ComboBox has changed the selected value?

I have a view that has 2 combo boxes (Call them ParentTypeCombo and ChildTypeCombo). Both of these combo boxes have the same backing drop down list (call it WorkItemTypes).
Using MVVM how can I know when the value was changed for these combo boxes? I have bound them to properties (Call them ParentType and ChildType). But as I recall, my setter will not be called by WPF.
I don't want to just go off the event on the combo box because that will go in the code behind, not the View Model.
(I saw an example using an ObservableCollection. But I confess I did not understand it. I used a value called CollectionViewSource that it does not explain what is or where it is obtained.)
Just bind the SelectedItem to a property in the ViewModel for both parent and child
<ComboBox SelectedItem="{Binding ParentSelectedItem}" ... />
// VM
public WorkItemType ParentSelectedItem
{
get { return _parentSelectedItem; }
set
{
if(value != _parentSelectedItem)
{
//HERE you know it has changed value.
_parentSelectedItem = value;
RaisePropertyChanged("ParentSelectedItem");
}
}
}
Also you can have only one collection on the view model and bind them to both combo boxes.
Set the ComboBox IsSyncronyzedWithCurrentItem property to true, than on your vm, call this CollectionViewSource.GetDefualtView([your workitem types]), the return type is ICollectionView or something similar, and it has a current changed event.

Resources