I have a simple LongListSelector without grouping option, lists some names. When a name changes in the source, the LongListSelector should have to update the list, but it shouldn't. Searching over the network I found that I have to use an ObservableCollection as data structure, beacause it has NotifyPropertyChanged event. Using an ObservableCollection instead of a List, nothing has changed: the LongListSelector does not update the items when I modify some name in the ObservableCollection.
The code is the same of this: http://code.msdn.microsoft.com/wpapps/LongListSelector-Demo-45364cc9
What should I modify to obtain an auto-update LongListSelector? I have to set NotifyPropertyChanged event or not? If yes, how?
The ObservableCollection auto updates when you change the collection itself and not a value inside one of its items.
It fires CollectionChanged when you add, remove etc... an item.
You should look at this especially simon's answer, so you can build a reusable object.
Related
I have a collection of items, which I have bound to an ItemsControl:
<ItemsControl ItemsSource="{Binding ProductCategories, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBlock Text="{Binding CategoryName}"/>
</ToggleButton>
I then have a second items collection which, in my view model, is based on a query, dependant on the above collection.
So, my requirement is to filter a list of products, based on the above category. The problem that I have is that the above binding is to a ProductCategory; so, while the set fires correctly for the 'IsSelected' property on ProductCategory, it doesn't notify that the 'ProductCategories' has changed.
ProductCategories is defined as:
public class ProductCategories : ObservableCollection<ProductCategory>
My first thought was that I could achieve this by using a DataTrigger; however, these don't seem to be available since WinRT. I could also use some kind of message notification for this, but I feel like this is something that should be achievable directly from the XAML binding.
So, my question is, is it possible to raise a notify that the parent class has changed, when the child class is changed.
DataTriggers are available in UWP using this nuget package https://www.nuget.org/packages/Microsoft.Xaml.Behaviors.Uwp.Managed
Here the link to the wiki https://github.com/Microsoft/XamlBehaviors/wiki/DataTriggerBehavior
Using this, you can invoke Command using DataTrigger binded to IsSelected.
So you're trying to filter one collection (Products?) by the selected item from another collection (ProductCategories)?
If so, you seem to be over thinking this slightly. Remove any 'IsSelected' concept from your ProductCategory class as this is display related and does not belong in your model. Then change the ProductCategories ItemsControl to a ListBox and bind the LsitBox.SelectedItem to a 'SelectedProductCategory' property in your view model as Mode=TwoWay, UpdateSourceTrigger=PropertyChanged. When the user selects an item in the ListBox, the 'SelectedProductCategory' setter will be called, at which point you can filter your second collection (remembering to call PropertyChanged if the collection doesn't support change notification).
Hope it helps.
I have a WPF application with a ListBox (called listMyItems) which is successfully bound to a class of MyItems that I created. I have a List of MyItems called currentMyItems which is then assigned as ItemSource to the ListBox. It all works fine, if I add an item to the currentMyItems it pops up on the list, etc.
The problem occurs when I try to remove the selected item in the ListBox. This is the code that I use:
currentMyItems.Remove((MyItem)listMyItems.SelectedItem);
The item disappears from the ListBox but the next time I update it, it pops back up as it was never deleted. Any tips?
I think you may be confused about how data binding works. When you bind a property, you are telling WPF to go look somewhere else for the value of that property.
When you bind the ListBox.ItemsSource property to currentMyItems, you are telling WPF to go look at the currentMyItems list to find its list of items. If currentMyItems is an ObservableCollection instead of a List<T>, then the UI will automatically receive a notification to update the bound value when you add or remove an item from the collection.
Based on what you say in the question, it sounds like you you have two collections, one of which is bound, and the other which is used to recreate the first collection anytime a change occurs. All that is not needed.
Just create one ObservableCollection<MyItem>, bind it to the ListBox.ItemsSource property, and then add or remove items from that single collection. It should work as you would expect.
<ListBox x:Name="listMyItems" ItemsSource="{Binding MyItems}" />
and
MyItems.Add((MyItem)listMyItems.SelectedItem)
MyItems.Remove((MyItem)listMyItems.SelectedItem)
If you're interested, I also have some beginner articles on my blog for WPF users who are struggling to understand the DataContext. You may want to check out Understanding the change in mindset when switching from WinForms to WPF and What is this “DataContext” you speak of?
If you bound it correctly to an ObservableCollection and currentMyItems is that collection. Than it means that you must have reloaded currentMyItems in meantime.
Also consider binding the SelectedItem property of your ListView - your view model doesn't have to know about the view at all.
Your source collection must be modufy (inherit from IList or ICollection). If your source collection does not support this method of your interface Remove, you can't remove item from source.
So, when you want to remove item you must cast ItemsSource to IList or ICollection:
var source = listbox.ItemsSource as IList ?? listbox.ItemsSource as ICollection;
and then check:
if (source == null) return;
then:
listbox.SelectedItems.ForEach(source.Remove);
listbox.Items.Refresh();
Make the currentMyItems<MyItem> an ObservableColection<MyItem>. This way it will raise a property change whenever modified and the UI gets updated accordingly.
By using ObservableCollection you will automatically get updates on the UI.
You should use an ObservableCollection instead of List.
A good thing is to always use ObservableCollection instead of List when something to do with UI
I have a listbox with items bound to an ObservableCollection.
Now, from within the viewModel, I need to cause an update to the UI.
I dont have a refernce to the listbox from my view model.
If I remove or add an item from my ObservableCollection, the ui gets updated.
Based on some other logic I need to update the UI...but the ObservableCollection is the same.
How can I update the UI WITHOUT either adding or removing items from my ObservableCollection?
Thanks
If you need to change your UI because you've edited the items in your collection, then you should arrange for those items to implement the INotifyPropertyChanged interface. If the objects within your collection have a PropertyChanged event, the UI will be listening for that event from individual items. (If possible, you could also change the items in your collection to be DependencyObjects with DependencyProperties, which accomplishes the same goal.)
If you really need to trigger a UI update when nothing at all about your collection has changed, the way to do it is to manually raise the CollectionChanged event. This can't be done with the ObservableCollection<> as is, but you could derive a new collection from that class, and call the protected OnCollectionChanged method from within some new, public method.
I've had a similar issue where I wanted to change the background on an item, but obviously neither the item nor the collection changed.
It was achieved by calling:
CollectionViewSource.GetDefaultView(your_collection_name).Refresh();
This refreshed the view from the view model without altering the collections
This is a good case for an extension method. It hides away the implementation in case it changes in future versions, can be modified in one place, and the calling code looks simpler and less confusing.
public static void Refresh<T>(this ObservableCollection<T> value)
{
CollectionViewSource.GetDefaultView(value).Refresh();
}
Usage:
myCollection.Refresh();
I am binding a BindingList two way to a listbox. The Binding list contains a number of images which apparently only update the listbox if items are added or removed from the binding list. How can I make it so that the bindinglist also raises the listchanged event when an item is modified?
EDIT: I find the problem I am having is that a property of an object is not being changed, rather the base object.
BindingList<ImageSource>();
This wont work however if I did this:
BindingList<Image>();
And then set the binding path to Image.Source, it would update correctly and this is because a property of the Image has changed but in the case of the first example, only a direct item in the list has changed. So how may I get the same behaviour as the second example?
FINAL EDIT : It seems that using ObservableCollection instead of BindingList fixes this issue. I was under the impression that they were identical in notifying of changes in the collection. Full answer below
The list does raise that event but only if the underlying items provides the proper notifications via INotifyPropertyChanged.
The BindingList differs from ObservableCollection in that BindingList does not notify that its direct items are changed (except when items are added or removed from the collection). ObservableCollection however implements INotifyCollectionChanged and INotifyPropertyChanged interfaces. This means that any change to direct items of an ObservableCollection are reported to the UI.
If you are using bindings to direct items and need to update items and not properties of those items, it seems that you have to use ObservableCollection. Another solution would be to derive from BindingList and implement INotifyCollectionChanged.
I am not an expert but this is what i have gathered during the last hour, if anyone has anything to add or correct please let me know.
I have an IEnumerable<> which lazy loads it's data. I want to just set a Combobox's ItemsSource to the IEnumerable, but when I do it goes and loads all the data anyway (which removes the point of lazy loading).
I've tried it with Linq-To-Sql as well since it seems to be a similar theory and it also loads all the data.
Is there an easy way to do this?
Try setting the IsAsync-Property in the ItemsSource-Binding of the ComboBox to True:
<ComboBox ItemsSource={Binding YourItemsSourceProperty, IsAsync=True}
SelectedItem={Binding YourSelectionProperty} />
If that does not change anything, have a look at this one:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/3d343489-90c4-4bdc-8bd9-1046ec9daf76
Maybe you will need to use IList instead.
Alternatively, you could use PriorityBinding, to fill the list with some temporary data until the final list is completely loaded.
Don't bind the control to the IEnumerable directly. Instead, bind it to a ObservableCollection (which is empty at the beginning.) Meanwhile, still do your lazy loading on the IEnumerable as usual (either triggered by drop down combobox or something else.) While the data is loaded or when you have enough data, add the items to that ObservableCollection to populate the comboBox.
I don't think the WPF ComboBox supports lazily loading the items from the ItemsSource. Why do you need to lazy load anyway, and when would you expect it to trigger the lazy load?
Bind your ComboBox's ItemsSource to an ObservableCollection.
Now whenever your IEnumerable lazy loads the data, add it to the ObservableCollection instantly
foreach(Item i in myIEnumerable)
{
myObsCol.Add(i);
}
This would update the UI once each item is added.
I am trying to do same thing. But as I investigated, if you want to use standard bindings on combobox (collection to ItemsSource and dataItem to SelectedValue/SelectedItem), it is necessary to write your own control.
Combobox is inherited from Selector and when you have bounded collection to ItemsSource property and you change your value of property that is bounded to SelectedValue/SelectedItem then the Selector call it's own private method FindItemWithValue(object value). This method walks through items in bounded collection from first until it finds equal value. That of course will make you collection to load all items before the selected one.
If you are willing to do your own custom class that will have a list, you can use INotifyPropertyChanged interface to tell that your collection has been modified. Or as use ObservableCollection as it has been already suggested