So I have this combobox, which ItemsSource is set to a List of objects.
What I want to do after that is change the Display value of one specific Item (the first on the list), because this label does not suit the context in some situations but does in others.
So far I found that you could add an item using the Add method, insert one using the Insert method, and remove one using RemoveAt.
But how do you update one ? I know I could use RemoveAt and Insert afterwards, but it would be a bit labor intensive, plus I would have to recreate the object with all its values...
Any ideas?
Either replace an item in your "List of objects":
myList[0] = new MyObject("Another display text").
For this (and Add, Remove etc) to work, your list would have to be an ObservableCollection<T> or any other that implements INotifyCollectionChanged.
Or modify the item itself:
myList[0].DisplayText = "Another display text";
For this to work, your MyObject class would have to implement INotifyPropertyChanged, you'd have to raise the PropertyChanged event when the DisplayText property is set, and you'd have to set the DisplayMemberPath or the ItemTemplate of your ComboBox correctly.
Take a look at the MVVM pattern for more information.
Related
I have a BindingSource which I use to bind to a grid. The binding source itself binds to a custom class. For instance
MyGrid.DataSource = MyBindingSource
'Bind the Binding source to data
For each classInstance as myClass in MyCollection
MyBindingSource.List.Add(classInstance)
Next
A user may add or delete items to/from this List. My aim is to save this updated List to the database. I need to determine if my binding source's list has changed (i.e. has items added to it, or has items removed from it).
I am aware that I could implement the INotifyPropertyChanged on my custom class, and exploit the OnPropertyChanged event, but my classes' property would never change in my case. The other solution that I can think of is to use the BindingSource's ListChanged event, and maintain a collection of all the added and the deleted rows there. Although this approach may work for me, I reckon its a bit flaky.
Does the binding source or a Collection (such as the IList in my case) provide any other properties that can help me determine the above?
I have bound my DataGrid to a DataTable and only few of the details are displayed in the grid. When I wanted to filter the DataGrid I created a View with my DataGrid's ItemsSource.
Code:
Dim myView As ICollectionView = CollectionViewSource.GetDefaultView(MyDGrid.ItemsSource)
myView.Filter = New Predicate(Of Object)(AddressOf filterFunc1)
Now When I do the search, the non-displayed fields are also included in the search.
Public Function filterFunc1(ByVal obj As Object) As Boolean
Dim filStr As String = "*" & TextBox1.Text & "*"
For Each item As String In obj.Row.ItemArray
**If item.ToLower Like filStr.ToLower Then**
Return True
End If
Next
Return False
End Function
Also I Have ComboBox fields in the DataGrid which are loaded separately from other DataTable's. Now I cant Include them in the search.
A screenshot from my App:
So how do I make a search that includes only the Text from Displayed part.
EDIT: Also how do I skip searching the null valued fileds? 'cause thats causing an exception in my case.
Well then...
Your question is pretty disjointed and I can't understand all of it - maybe that's why you didn't get an answer so far. Skipping null fields is simply a matter of adding a new condition in filterFunc1 - if Convert.IsDBNull(item) then continue for (assuming item is a field in a DataRow, of course).
However, this programming style is pretty foggy and I'd recommend at the very least being more clear on which columns you filter, and the types of objects in the columns. A much better approach would be to map the data you're getting from the database to actual objects in your application - that allows for more type-safe programming. I think the main problem here is that nobody can really tell what's going on there from a few lines of code because nobody can make any assumptions about what kind of objects are there.
About the items in the ComboBox, no idea what kind of difficulties you're having, you might want to clear that up a bit.
you could maintain, instead of simply strings, structures containing both captions and IDs, like say
public class YourComboItem
public property Id as string [get/set]
public property Title as string [get/set]
end class
Then bind your ComboBox's ItemsSource to a collection of these items retrieved from the database, and set DisplayMemberPath to Title and ValueMemberPath to Id. Then you can use the ComboBox's SelectedValue to get the selected ID. As you can see, having objects instead of raw data structures can have quite some advantages.
Of course, I described getting the SelectedValue directly from the ComboBox, while a much better architecture would be MVVM, with the ViewModel containing an ObservableCollection(Of YourComboItem) and the ComboBox's ItemSource bound to it with an actual binding. Then you can also bind the SelectedItem to a property in your ViewModel, and have the item as a whole, including both Id and Title, to work with without knowing anything about your user interface. Alternatively you could have an ICollectionView generated from the collection of items and bind the ItemsSource to that, then you'd have the selected item in the ICollectionView's CurrentItem property.
I'd really recommend reading up on MVVM (Model-View-ViewModel) to make your work with WPF a whole lot easier.
I have a listbox bound to a collection. I would like the ListBox to always reverse the order of the items. This handler--hooked up to the control's load event--works for the initial load, but not thereafter. Ive tried using the SourceUpdated event but that doesnt seem to work.
How do I maintain a constant active sort?
MyList.Items.SortDescriptions.Add(New SortDescription("Content", ListSortDirection.Descending))
How is the collection stored that supplies the items for the ListBox? It should be a collection that supports INotifyCollectionChanged. The framework provides ObservableCollection<T> which you can use.
In the constructor of your ViewModel (or wherever the collection lives), you then get the DefaultView for adding the SortDescription. The CollectionView is like a layer on top of your collection, which you can use to sort, group, filter, etc. the items without actually affecting the underlying data source. The framework creates a default one for you. To get a reference to it, you can use code similar to the following:
var collectionView = CollectionViewSource.GetDefaultView(Widgets);
if(collectionView == null)
return;
collectionView.SortDescriptions.Add(new SortDescription("Content", ListSortDirection.Descending));
With that in place, you should be able to add items to the ObservableCollection<T> and the sort order will be maintained.
If your source collection is a List<T> or some other collection that doesn't implement INotifyCollectionChanged, there is no way WPF can detect when an item is added. You need to use a collection that implements INotifyCollectionChanged, like ObservableCollection<T>.
Also, the items in your collection need to implement INotifyCollectionChanged so that changes to the items are taken into account
I have a Listbox that I binds to a resource (sort) CollectionViewSource in my XAML. Then in my cs code I set the CollectionViewSource source to List of objects (class level field)
I then have "remove button" that checks the selected items in the Listbox and removes them from the List of objects (class level field).
I thought the Listbox should update automatically since the items source updated.
Am I missing a step or property setting ?
Or am I missing something about how binding works?
tep
The class that contains your list of objects must implement INotifyPropertyChanged and you must raise the notification event when the list changes, passing in the name of the property that changed. This is what notifies the UI that it must update anything bound to that property.
Alternatively, make your collection of objects an ObservableCollection<T> and that will do the notifying for you.
I have a strange "problem". Could someone explain me why :
If I have in an ObservableCollection, twice (or more time) an item with the same value, then the selections of those values in the ListBox won't work properly ?
In fact, what the ListBox is doing when I click on an item(Even in single item selection) : It selects the first item from the ObservableCollection collection with a matching value. so in the case if multiple items with same value are in the collection, then only the first one will be selected !
Because objects you entered to collection have same references. you should create new instances in each case or override Equal function and write your logic for identifying items. WPF ListBox calls Object.Equal function to identify if the items are same.
Hope this helps
You need to create a new object to hold each object.
I.e.
MyCollection.Add(new MyContainer() { Data = myObject } );
This way the listbox will select the objects properly as it has unique containers.
This would be implicit if you were using ViewModels