Hi!
I'm using an UltraComboEditor that uses Data Binding to get an Id out of an underlying business object which is used to select appropriate item from the items list. If another item is selected in the combo the Id is changed in the business object via the data binding which is fine.
I handle the ValueChanged event of the UltraComboEditor since I have to update another property 'Name' on same business object. This business object implements the INotifyPropertyChanged interface i.e. when 'Name' is set event OnPropertyChanged("Name") is fired causing data binding to fetch all visible properties again. This causes also the UltraComboEditor to display the item associated with the Id from the business object which is the original one thus the selection can never be changed.
I found a solution which works but my feeling is that it is more a workaround. In the ValueChanged event handler of the UltraComboEditor I explicitely set the 'Id' before setting 'Name' I. What I don't like on this solution is that 'Id' is updated again through the data binding.
Comments are welcome, Wolfgang
I think I have got around the problem by using the SelectionChangeCommited event. This appears to run after the bound object has been updated.
I'm not sure it would work in every circumstance as I presume it is only triggered when the change is driven by selecting from the dropdown and not when the text is edited directly? In my case I had a dropdown list rather than combo so it appears to have done the trick.
I still feel that the bound property and the combo value should be consistent for code in the ValueChanged event or there should be a ValueChangeCommited event that we can use instead.
I have the exact same problem. I think the main problem here is that combo doesn't update the value of the property on the object it is bound to until after the ValueChanged event has fired. So when code runs in the ValueChanged the value of the bound object property and the combobox value are different.
This means that if you change any other property on the bound object if fires the PropertyChanged event which causes all the values to be copied to the bound controls again thus overwriting the change to the combo box value you just made and triggering the ValueChanged event again.
Here's some contrived VB code that will hopefully makes sense. Just so you know, I'm typing this by hand and will leave some bits out - so its unlikely to compile :)
----------------------------------------------------------------------------------------------
Here's the business class (it's missing the propertychanged event):
Public Class MyClass Implements INotifyPropertyChanged
Public Property Property1() As MyEnum Get Return m_property1 End Get Set(ByVal value As MyEnum) If m_property1<> value Then m_property1= value OnPropertyChanged("Property1") End If End Set End Property
Public Property Property2() As Integer Get Return m_property2 End Get Set(ByVal value As Integer) If m_property2<> value Then m_property2= value OnPropertyChanged("Property2") End If End Set End Property
End Class
Here's the enum:
Public Enum MyEnum Zero = 0 One = 1 Two = 2End Enum
And here's the binding code (m_myObject is an instance of MyClass held by the form):
cboMyCombo.DataSource = [Enum].GetValues(GetType(MyEnum))cboMyCombo.DataBindings.Add("Value", m_myObject, "Property1", False, DataSourceUpdateMode.OnPropertyChanged)
Here's the ValueChanged event:
Private Sub cboMyCombo_ValueChanged(ByVal sender As Object, ByVal e As EventArgs) Handles cboFrequency.ValueChanged
' At this point m_myObject.Property2 does not equal cboMyCombo.Value
' Next Line causes PropertyChanged event to fire ...
m_myObject.Property2 = 5
End Sub
The scenario is this:
On the form I change the combo value from Zero to One. This causes the ValueChanged event to fire. In that event handler I set Property2 to 5. Assuming it was some other value before, this causes the object to trigger the PropertyChanged event.
This in turn causes the bindings to refresh.At this point in time cboMyCombo.Value is One, but m_myObject.Property1 is still Zero, so the value of the combo box gets set back to Zero by the binding refresh and even worse the ValueChanged event is triggered again.
The problem would go away if the combobox set the value of the bound object BEFORE it calls ValueChanged.
Sorta sounds like a bug to me!?
qbupoew said:The easiest way to achieve that is to add a property Capital to the Address class and whenever a new State is selected in the combo the new Capital value is displayed in the UltraGrid. I'm not storing that into database, it's just for the purpose of displaying it in the UltraGrid. If you know a better solution for updating the data in the UltraGrid without adding the Capital property to the Address class maybe you can share that information?
A better way would be to add an unbound column to the grid. that way the extra field does not exist in the data source, only in the grid, and this would avoid the whole problem you are having.
qbupoew said:Another purpose, that is feasible in our project, is that we have to store some kind of snapshot. If the Address object is related to a customer's order you want to store the Capital name that was valid at that time when he made the order. Let's say a customer from California makes an order so we would store 'Sacramento' as the Capital. If over time Gouverneur Arnold Schwarzenegger decides that 'San Diego' is the new Capital of California, updates the State data for California appropriately we still would have 'Sacramento' on the Address object for that customer's order taken some time ago. Of course it's rather unlikely that something happen with a state's capital :-) but if you think on a list of company names presented in the Combo it's very likely that a company's name changes over time and due to e.g. legal reasons you have to store the company's name from the time when an order has been taken into the Address object.
I guess I can kinda see how that might be useful. In such a case, though, it would probably be better to add a new State entry for the same state with a different capital and use the new one going forward so no data is lost. But since you are not storing the information in the database, anyway, I assume you are just talking theoretically here.
Hi Mike,
Thanks for your reply. You are totally right that the Capital is duplicated data on the Address and from the data model point of view it is redundant but there is at least one reason why we do that. The list of Address objects is shown in a UltraGrid and one column shown there is the Capital. Beneath the UltraGrid there is the UltraComboEditor to select the U.S. state that should also change the Capital name for the activated Address in the UltraGrid. The easiest way to achieve that is to add a property Capital to the Address class and whenever a new State is selected in the combo the new Capital value is displayed in the UltraGrid. I'm not storing that into database, it's just for the purpose of displaying it in the UltraGrid. If you know a better solution for updating the data in the UltraGrid without adding the Capital property to the Address class maybe you can share that information?
Another purpose, that is feasible in our project, is that we have to store some kind of snapshot. If the Address object is related to a customer's order you want to store the Capital name that was valid at that time when he made the order. Let's say a customer from California makes an order so we would store 'Sacramento' as the Capital. If over time Gouverneur Arnold Schwarzenegger decides that 'San Diego' is the new Capital of California, updates the State data for California appropriately we still would have 'Sacramento' on the Address object for that customer's order taken some time ago. Of course it's rather unlikely that something happen with a state's capital :-) but if you think on a list of company names presented in the Combo it's very likely that a company's name changes over time and due to e.g. legal reasons you have to store the company's name from the time when an order has been taken into the Address object.
Kind regards, Wolfgang
Hi Wolfgang,
Okay, I think I understand the issue now.
My first question is... why have a Capital field on the Address table? This seems like an unnecessary duplication of data. The Address table already has a state id, and it can look up the capital based on that StateId, so having the Capital as a field in the Address doesn't really make sense and makes more work for you, because now you have to keep the two fields in synch.
I don't see any other solutions besides the ones you list here. Your second solution, while less intuitive to the user, seems like the safer one from a coding perspective, since it handles any time the address field is updated, not just through the Combo. If you application is updated in the future and a second method is provided which allows changing the StateId, the developer will have to know to also update the Capital at the same time. And again, this is another argument for not storing duplicate data.