I'm currently building an application that utilizes a ComboBox to allow the user to select from a dynamic list of String objects contained within a BindingList object. However, the BindingList is a member of a child class belonging to the main class, which appears to be causing some issues.
When the ComboBox's data source is set initially within the main class via:
this.comboBox.DataSource = this.childClass.dataList;
the contents of the ComboBox appear as expected. However, when the contents of the list changes, the contents of the ComboBox are not updated.
If the BindingList object belongs to the main class, the ComboBox updates without any issues. It would appear that the parent class is not receiving the events that signal that the list has been updated.
Any ideas?
After looking at a similar question I asked (and answered) last year:
Adding/Removing COM Ports from a ComboBox in C#
, it seems I've (re)discovered the solution. The problem was with how the strings were being added to the data source. Because the list was being augmented in another thread, there was an issue with the ComboBox control being updated. By utilizing a delegate and the Invoke() method, the contents of the ComboBox are now updated as expected.
Related
I've got a ListBox and a DataGrid where the ListBox shows a subset of the list of the DataGrid. I created the two lists that the control's are bound to separately, however both control's SelectedItem are bound to the same property in the view model. I need to have both controls select the same item when the user clicks on either control's items unless the user clicks on the DataGrid on an item that is not in the ListBox's subset (then the ListBox should not have anything selected).
I'm guessing since the lists were created separately they are not the same object so is there a way to provide some sort of comparison logic to the controls to select an item that essentially has the same name (or value or some sort of criteria)? If that doesn't exist then I guess the best way would be to create the subset list of objects from the exact same objects in the superset.
I'm guessing since the lists were created separately they are not the same object
You could add the very same object to two different collections, e.g.:
YourType obj = new YourType();
list1.Add(obj);
list2.Add(obj);
This should solve your issue.
You could also override the Equals method of YourType as suggested in the comments but you shouldn't have to if both collections references the same objects, which they should since the second is a subset of the first.
I have a property (text box) which is a part of a list. And that list is a property in another list (class). Now when I write something in that text box , the ancestor one should get updated. I have tried RaisePropertyChanged() but its not working out. Can anyone provide me with right syntax??
When binding lists you should take a look at INotifyCollectionChanged. RaisePropertyChanged propagates that the list itself (not just one item in it) changed. If bound to a GUI the GUI will check for a change and sees the same old list in place, so it takes no further action.
I'm writing a BHO that uses an ElementHost to host a WPF User Control. Within the user control, I have a DataGrid that binds to an Observable Collection. Everything functions fine, except that the content is not being read by screen readers (I'm using NVDA to test, but QA is using JAWS).
I'm restricted from copy & pasting code on a public forum, but I can describe the layout that I'm creating. There are two datagrid. One contains all of the items from the Observable Collection and the other is a subset of the items. Each datagrid is in a separate Tab Item of a TabControl. As I stated, there is an ObservableCollection that holds my business objects. Each object binds to a row in the datagrid. Several of the columns require that I display multiple properties from the business object, so I'm using the DataGridTemplateColumn. Within the CellStyle, I have 3 DataTemplates set up; one for edit, one for add and one for view. The view DataTemplate is exactly the same as the DataGridTemplateColumn.CellTemplate.
One of the columns holds my action buttons. One of the buttons is an edit button which simply applies the edit template to the rows cells. Outside of the datagrid, I have a button that will add a new default item to the ObservableCollection, call UpdateLayout on the datagrid, then set the DataTemplate of the new item to the add template.
There is also a button that will grab information from a remote server, convert it to business objects and add them to the Observable Collection. The datagrid loads the new information with no problems.
When I use the function to pull the objects from the database, none of the information will be read by the screen reader. If I click the edit button, everything is read as expected. After returning to the "view" DataTemplate, everything reads as expected. If I use the Add button, everything reads as expected.
To make this more complicated, if I edit an item in one tab page and get it to be read, then go to the other tab page and come back, it's no longer reading.
I have a feeling that it's related to the how binding and templates interact, but I don't know enough about either to figure out a direction to go in resolving this.
Any help would be appreciated.
EDIT: While I was creating the dummy project to show the issue, I discovered that the problem is not just limited to Template Columns. I created a business object with string properties, created an ObservableCollection with 10 objects in it and bound each property to a DataGridTextColumn, and it only reads the grid name and column index...the contents are never read.
Basically, I'm wondering how it is actually efficient here.
Sample code:
void GetItems()
{
foreach (var item in items)
myObservableCollection.Add(item);
}
Won't this fire off the CollectionChanged event every time causing the UI to have to refresh everytime? Or does it do it so that it waits til the GetItems function is done?
Basically, it seems that WPF handles it very well, and I'm wondering how they did that.
Optimizing Performance: Data Binding provides some background on how data bindings are resolved, including the performance implications of different items sources. Take a look at the Binding to an ItemsSource section.
Consider a scenario in which you have a CLR List object that holds
a list of employees that you want to display in a ListBox. To create a
correspondence between these two objects, you would bind your employee
list to the ItemsSource property of the ListBox. However, suppose you
have a new employee joining your group. You might think that in order
to insert this new person into your bound ListBox values, you would
simply add this person to your employee list and expect this change to
be recognized by the data binding engine automatically.
That assumption would prove false; in actuality, the change will not
be reflected in the ListBox automatically. This is because the CLR
List object does not automatically raise a collection changed
event. In order to get the ListBox to pick up the changes, you would
have to recreate your list of employees and re-attach it to the
ItemsSource property of the ListBox. While this solution works, it
introduces a huge performance impact. Each time you reassign the
ItemsSource of ListBox to a new object, the ListBox first throws away
its previous items and regenerates its entire list. The performance
impact is magnified if your ListBox maps to a complex DataTemplate.
A very efficient solution to this problem is to make your employee
list an ObservableCollection. An ObservableCollection object
raises a change notification which the data binding engine can
receive. The event adds or removes an item from an ItemsControl
without the need to regenerate the entire list.
Update time for 1 item (ms)
To a CLR List object = 1656 ms
To an ObservableCollection = 20 ms
WPF never binds directly to a collection. If you specify a collection as a binding source, WPF actually binds to the collection's default view.
A collection view is a layer on top of a binding source collection
that allows you to navigate and display the source collection based on
sort, filter, and group queries, without having to change the
underlying source collection itself. A collection view also maintains
a pointer to the current item in the collection. If the source
collection implements the INotifyCollectionChanged interface, the
changes raised by the CollectionChanged event are propagated to the
views.
The event will fire for every change.
The GUI does not have to react and refresh every time, it can postpone that.
I know WinForms will optimize this, I think WPF has a similar approach.
If you want to see how often the UI requests the fresh results expose it as a public property and put a debug line in the get (assessor) of the public property for myObservableCollection.
I'm working on a project that controls multiple devices over USB and intercepts the WM_DEVICECHANGE events from Windows to manage currently connected devices and plugin modules using those devices. There exists a combobox on the main form that (should) display all available devices (the custom object) and be dynamically updated in the event of either device arrival or removal.
Now, every tutorial that I have read including some from here have directed me to set the DataSource property of the combobox to the List of objects that I have, and leave the DisplayMember/ValueMember property blank to display ToString() and to return the object as the value.
In some instances I have tried (such as post instantiating the List and populating it with sample/real objects) the combobox populates, however upon removal or arrival, the collection in the combobox does not update even when reassigning the List to the combobox's DataSource property after every device arrival/removal method.
EDIT: Oh right... the question...
How do I databind the collection of (custom objects returned as the values) dynamically such that it can handle sudden changes (additions/removals) to the list's contents?
EDIT 2: Sorry I didn't make this more clear, wasn't aware of how pervasive WPF has gotten, but this is a WinForms project.
Thanks in advance for any help you can provide. :)
even when reassigning the List to the
combobox's DataSource property after
every device arrival/removal method.
After reassigning, you need to call .DataBind() again.
If you're using .net 3.5 or above, you can use an ObservableCollection to have the list update automagically.
I'm not sure if you're using WinForms or WPF. I'm assuming WPF as nobody should start out on WinForms nowadays...
You need to change your List to an ObservableCollection<T>.
The WPF binding model relies heavily on a magic subsystem of fairies and warlocks (not mocking you, I'm actually serious). They have their own language for informing each other that something has changed between the DataContext and UI. These are primarily the DependencyObject/Dependency properties, INotifyPropertyChanged and INotifyCollectionChanged, and the ObservableCollection<T>.
By proper use of these totems, changes in your ViewModels/Models (the stuff you stick in the DataContext and/or bind to the DataSource) will be reflected on the UI.
I don't know about that ToString() bit. I always set the DisplayMember to the Property I want to display. I don't care about the ValueMember because the SelectedItem is my Object.
DataBind doesn't apply if this is a WinForms project, which it sounds like. (USB and stuff)
I don't do anything funky in my project when up update the data in a ComboBox, I just set the DataSource again.
EDIT:
You could try using a BindingList rather than a List also.
http://msdn.microsoft.com/en-us/library/ms132679.aspx