I have an MMVM project and with one of my View/ViewModels have an issue with databinding.
The view consists of a few combo boxes, and the user is required to select a value from each combox box. After a value is selected, I need to populate the next combo box.
How can I ensure the databinding works correctly in WPF, since only the the first combo box's value is populated on load. The others are all null, and seem to break all databinding to those attached controls. I have INotifyPropertyChanged implemented on my ViewModel, but I think things are getting lost due to the initial null values.
I would use ObservableCollections for each ItemsSource.
Create a new instance of each collection before binding them to your ComboBoxes. Leave them empty, but instantiated so that they are not null.
Then, when you are affecting the content of each combobox, directly modify each collection respectively rather than rebinding the ItemsSource (though I assume you are not doing that since you are using MVVM).
Related
Scenario
ComboBox C depends on the selected value of ComboBox B, which depends on the selected value of ComboBox A. All of these ComboBoxes are in a DataGrid.
Common Road Blocks:
The User must be able to add new rows (This Requires a ItemsSource item type that has a parameterless constructor).
To access the database to populate the List of Available Options for the Comboboxes, the current project would require the Database Credentials/DataContext be passed into the Constructor.
Attempt 1
I've tried using 3 CollectionViewSources, one for each of the ComboBoxes (Concept Code Here), but the SelectedItem of the ComboBox gets automatically selected in the other DataGrid rows. I need to find a way to isolate the CollectionViewSource to each row.
I've considered just adding the CollectionViewSource data to each of the DataGrid Items so I can just bind to it that way, but I have to access the database to generate the CollectionViewSource.
I also tried not sharing the CollectionViewSource as seen in this question, but that destroyed the link between the 3 ComboBoxes, as well as the Rows. If I could just set the CollectionViewSources to be shared within each DataGrid Row and not between each of them, I think it would work. I just can't find a way to do that.
Attempt 2
I've looked at this question: How to get cell level ComboBox for WPF DataGrid?
This would work, but the User needs to be able to add rows to the DataGrid. The example code in that question also uses a parameterless constructor. I am in a situation where access to the database to populate the lists would have to be passed into the constructor.
The Question
How do I do this correctly?
Bind to a List or ObservableCollection, not a CollectionViewSource
CollectionViewSource tracks the Current Item, so changing the value in one ComboBox will change it in all ComboBoxes
I have two seperate WPF Comboboxes both of them bind to the same object to populate their values. However, when I change the selection in one combobox, the selection in the other combobox is changed to the same as the first, and vice versa. This is not the behavior I want, I want only want to bind the content of the comboboxes to a single source without mirroring their selections. I am binding to a BindingList.To bind I use
ItemsSource="{Binding}"
and
comboBox1.DataContext = bindingList;
What do I need to do to unlink the selections of these two comboboxes?
The way these actually work bind the scenes is by wrapping the collection in an instance of ICollectionView, which maintains the current selected item (amongst other things).
To get the behaviour you want, just set the DataContext of each combo box to:
new ListCollectionView(bindingList);
I have a two column combobox, and a textbox, bound to xml data.
The textbox shows the equivalent of the comboboxes second column of the currently selected item.
I've bound the datacontext of the textbox to the SelectedItem in the combobox, which then updates if you select a row in the combobox. Now, I'd it so that if you type something into the textbox that corresponds to a value in the 2nd column of the combobox, it selects that row.
I realise this is slightly circular.
I've managed it before in winforms, by effectively suspending events when the CombobBox OnSelectedItemChanged fires and updates the textbox or OnTextChange fires and updates selectedItem.
The idea is that the user can either select an option from the combo, or if they know a short code (in this case, country ISO), they can just type it in and immediately see the appropriate country selected in the combobox.
Is it somehow possible to bind the selectedItem in the combobox to the textBox in addition to the underlying data (and indeed does that idea make any sense?), or possibly do some sort of two-way-binding between these elements?
I'm hoping there's a simpler solution than dependencyproperties-- ideally something purely in xaml, but appreciate as I'm new at WPF, I've no idea if this is even possible.
Thanks!
Mike
If you've got a ViewModel you can two-way bind each to the same property of that, and this is probably the best way to do it.
I am using LinqToSql as my datasource, let’s say I query a list of programmers from a table and then loop through that data populating an ObservableCollection. (First question, is this part wrong? It just seems weird to query data into a list and then loop through it to populate another list)
Next, when I databind my ObservableCollection of programmers to a ListBox. Then I bind the selectedItem of the Listbox to a TextBox. I understand that when I select an item in the ListBox the textbox will be updated and when I make a change in the textbox, the ListBox will get updated and as a result the ObservableCollection that the listbox is bound to will also be updated.
What I don’t completely understand is what the best practice is to get the data from the OC back into my original datasource. Do I just loop through the observable collection commiting my changes by updating each record? That doesn’t seem terribly efficient.
Thanks so much for your help!
-Josh
This is purely a view-model issue. You have complete control over all the objects and properties on the data side of the fence. Sometimes you have a simple arrangement where the user can only edit a single record, databinding does all the work, and you just write it back to the database when the user clicks save.
If you have a lot more data being displayed and any one piece of it can be modified by the user, then it is probably wise for you to keep a dirty flag in the object itself that records whether any of the properties have been changed. That way, you can efficiently save back just the modified entries.
Since your objects probably support INotifyPropertyChanged and your collections are observable, you can even automatically detect and manage the dirty flag. Or it might be simpler to just set dirty to true in all of your setters.
In any case, this information can even be useful to the user. For example, a user-interface can show unsaved records in bold or with some other convention.
The ObservableCollection is not the only one collection which you could use in wpf. But it is standard collection allows wpf to automatically update ui item containers like ListBox on collection changes like addition or removal of an item. You can't do it with List.
When the user modifies a textbox in ListBoxItem the ObservableCollection is not updated cause you don't add or remove or reorder items in the collection. You change the property in one of the items.
The ListBox contains a list of ListBoxItem containers, one for each item in collection specified as an ItemsSource.
The DataContext of each ListBoxItem is set to the corresponding item stored in ObservableCollection. So, if you change the text in TextBox in code, the binding engine will change the property of that item specified for TextBox.Text in binding. Nothing to change or update for the ObservableCollection object.
In the setter of such item's property the PropertChanged event of INotifyPropertyChanged interface are usually raised. That is also the usual the place to set up a dirty flag. Then you could also commit changes immediately from there, keep some list of dirty objects or search for them on commit like:
items.Where(item => item.IsDirty)
Also there are good tools like Snoop and WPFInspector, which greatly help you to understand the wpf app visual tree and datacontexts for each element
I've got a Combo Box that is databound to an ObservableCollection of items. I would like to have a default selected item that is (None) that would set the value of the property I've bound to "SelectedValue" to null.
I think there ought to be a way to achieve this with some combination of Style/DataTemplate/TemplateSelector. I'm trying to design this with MVVM in mind, so I'd like something that doesn't use codebehind and is as reusable as possible. I'd also like the benefits of the ObservableCollection (updating the collection causing the control to rebind) to remain intact.
Bonus part B:
I would like to also be able to append an extra visual element to the bottom of an ItemsControl as well. I was thinking it would be easy to change the DataTemplate if I knew how to trigger it on the last item of a collection. Willing to entertain other options here.
The simplest way I've found to do this is to insert a "special" value into the underlying collection, and display the "(None)" text when it's selected. Obviously then you need to run your binding through a converter to take this value into account and return null when it's selected. (See this question of mine which was a result of me trying to add an actual null value to a ComboBox's underlying collection.)
Having said that, it might actually be possible to do what you want with the CompositeCollection class. You could make a separate collection (with only one item - your Null item) and bind your ComboBox to both it and your original collection through the CompositeCollection.