Suppose that you have an IBindable Generic.List of Entity Framework Customer Entities that serves as a BindingSource.DataSource and that serves as a WinCombo.DataSource. If the user selects a WinCombo row that differs from its initial row, the WinCombo attempts to update the 1st row's EF Entity properties with the values of the 2nd row's EF Entity properties.
This fails because one of the values that it attempts to update is the primary-key CustomerID. The Customer Entity's { set } for Customer ID throws an error.
But none of this should have happened in the first place. The user is merely selecting a different row - nothing has been edited - there's no reason to write anything. I can't set e.Cancel = true w/in the WinCombo_Validating() method because WinCombo is attempting to { set } the CustomerID value BEFORE VALIDATION !
What is up with this wackiness?
From the Call Stack, it looks like the MS CurrencyManager is interpretating a BindingSource.Position change as a change in record state (see bolded and especially underlined calls):
System.Data.Entity.dll!System.Data.Objects.EntityEntry.VerifyEntityValueIsEditable(System.Data.Objects.StateManagerTypeMetadata typeMetadata, int ordinal, string memberName) + 0x8e bytes System.Data.Entity.dll!System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(string entityMemberName, object complexObject, string complexObjectMemberName, out System.Data.Objects.StateManagerTypeMetadata typeMetadata = null, out string changingMemberName = null, out object changingObject = null) + 0x189 bytes System.Data.Entity.dll!System.Data.Objects.EntityEntry.EntityMemberChanging(string entityMemberName = "JobReleaseID", object complexObject, string complexObjectMemberName) + 0x38 bytes System.Data.Entity.dll!System.Data.Objects.EntityEntry.EntityMemberChanging(string entityMemberName) + 0x28 bytes System.Data.Entity.dll!System.Data.Objects.ObjectStateEntry.System.Data.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(string entityMemberName) + 0xb bytes System.Data.Entity.dll!System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanging(string property) + 0x62 bytes
> Durcon.Base.Data.dll!Durcon.Base.Data.JobRelease.JobReleaseID.set(long value = 414262) Line 5612 + 0x11 bytes C# [Native to Managed Transition] System.dll!System.SecurityUtils.MethodInfoInvoke(System.Reflection.MethodInfo method, object target, object[] args) + 0x5f bytes System.dll!System.ComponentModel.ReflectPropertyDescriptor.SetValue(object component = {Durcon.Base.Data.JobRelease}, object value = 414262) + 0x11b bytes System.Windows.Forms.dll!System.Windows.Forms.BindToObject.SetValue(object value) + 0x63 bytes System.Windows.Forms.dll!System.Windows.Forms.Binding.PullData(bool reformat, bool force) + 0x159 bytes System.Windows.Forms.dll!System.Windows.Forms.BindingManagerBase.PullData(out bool success = true) + 0x73 bytes System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.CurrencyManager_PullData() + 0x3a bytes System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.EndCurrentEdit() + 0x21 bytes System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.ChangeRecordState(int newPosition = 1, bool validating = true, bool endCurrentEdit, bool firePositionChange = true, bool pullData = false) + 0xbc bytes System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.Position.set(int value) + 0x42 bytes Infragistics2.Win.UltraWinGrid.v10.3.dll!Infragistics.Win.UltraWinGrid.UltraCombo.SyncSelectedRowWithCurrencyManager(bool targetSelectedRow) + 0x114 bytes Infragistics2.Win.UltraWinGrid.v10.3.dll!Infragistics.Win.UltraWinGrid.UltraCombo.SelectedItemChangeHelper(Infragistics.Win.UltraWinGrid.ComboSelectedItemChangeContext context = SelectedIndex, object newData) + 0x9a9 bytes Infragistics2.Win.UltraWinGrid.v10.3.dll!Infragistics.Win.UltraWinGrid.UltraCombo.OnActiveRowChange
(Infragistics.Win.UltraWinGrid.UltraGridRow newActiveRow, bool scrollIntoView) + 0x8b bytes Infragistics2.Win.UltraWinGrid.v10.3.dll!Infragistics.Win.UltraWinGrid.UltraGridBase.SetActiveRow(Infragistics.Win.UltraWinGrid.UltraGridRow row = {Infragistics.Win.UltraWinGrid.UltraGridRow}, bool scrollIntoView) + 0x1ca bytes Infragistics2.Win.UltraWinGrid.v10.3.dll!Infragistics.Win.UltraWinGrid.UltraGridBase.ActiveRow.set(Infragistics.Win.UltraWinGrid.UltraGridRow value) + 0x23 bytes Infragistics2.Win.UltraWinGrid.v10.3.dll!Infragistics.Win.UltraWinGrid.UltraDropDownBase.Infragistics.Win.ISelectionManager.ActivateItem(Infragistics.Shared.ISelectableItem item) + 0xc0 bytes Infragistics2.Win.v10.3.dll!Infragistics.Win.SelectionStrategySingle.OnMouseDown(Infragistics.Shared.ISelectableItem item = {Infragistics.Win.UltraWinGrid.UltraGridRow}, ref Infragistics.Win.MouseMessageInfo msginfo = {Infragistics.Win.MouseMessageInfo}, bool forceDrag = false) + 0xa5 bytes Infragistics2.Win.v10.3.dll!Infragistics.Win.SelectionStrategySingle.OnMouseDown(Infragistics.Shared.ISelectableItem item = {Infragistics.Win.UltraWinGrid.UltraGridRow}, ref Infragistics.Win.MouseMessageInfo msginfo = {Infragistics.Win.MouseMessageInfo}) + 0x2c bytes Infragistics2.Win.v10.3.dll!Infragistics.Win.SelectionStrategySingle.OnMouseMessage(Infragistics.Shared.ISelectableItem item = {Infragistics.Win.UltraWinGrid.UltraGridRow}, ref Infragistics.Win.MouseMessageInfo msginfo = {Infragistics.Win.MouseMessageInfo}) + 0x3d bytes Infragistics2.Win.v10.3.dll!Infragistics.Win.ControlUIElementBase.ProcessMouseDownHelper(object sender = {Infragistics.Win.UltraWinGrid.ComboDropDownControl}, System.Windows.Forms.MouseEventArgs e = {X = 22 Y = 52 Button = Left}) + 0x732 bytes Infragistics2.Win.v10.3.dll!Infragistics.Win.ControlUIElementBase.ProcessMouseDown(object sender = {Infragistics.Win.UltraWinGrid.ComboDropDownControl},
...
Hi,
That's correct. The CurrencyManager automatically updates when you change the current position. The combo has no control over this.
But... UltraCombo does not update the position of the CurrencyManager by default. It only does this if you explicitly set SyncWithCurrencyManager to true.
So you probably just need to find out where your code is setting it to true and take that out.
mduff said:Who wouldn't want that?
Anyone who is using the combo to select a value in a field. For example, if you are displaying addresses and you have a combo displaying the State, you would not want the combo to update the CurrencyManager position.
In fact, in such cases, the positioning of the BindingManager could cause you some problems - like suppose you are also displaying the list of States and letting the users edit them. Okay.. you would never let users edit the states, but you get the idea. :)
In your case, where you are using it for Navigation, it makes sense to set SyncWithCurrencyManager to true.
mduff said:But here's the crux of my post. My BindingSource.DataSource is a list of Entity Framework Entities. That BindingSource is the WinCombo.DataSource. When the user clicks off of WinCombo Row #1 and onto WinCombo Row #2, WinCombo declares a data edit and BindingSource tries to overwrite the values of EF Entity #1 with those of EF Entity #2.
Well, obviously that's not right. But I don't see how that could happen because of the Combo. It sounds like something is set up incorrectly, like you are using the Combo(s) to both pick a record to edit and also binding the edit portion of the combo to an individual field within the same table.
Are you calling combo.DataBindings.Add on the same combo with SyncCurrencyManager to true? And if so, are you binding the Combo's Value or Text to a field on the same table that it's displaying as it's list?
If so, then you just answered your first question.
Uh, I'm starting to feel a little like a dog chasing his tail here...
I'm using this WinCombo more as a record Navigator rather than a data entry control.
Yes, my WinCombo.SyncWithCurrencyManager = true. When the user clicks on a row that differs from the initial ActiveRow, I want the row position of my WinCombo.DataSource[Forms.BindingSource].DataSource to respectively move to the same Position as the row on which the user clicked. I'll update labels based on the values of the newly selected DataSource member.
Who wouldn't want that? Why does SyncWithCurrencyManager exist as a property at all? When is WinCombo.ActiveRow.Index != WinCombo.DataSource.Position a good thing?
But here's the crux of my post. My BindingSource.DataSource is a list of Entity Framework Entities. That BindingSource is the WinCombo.DataSource. When the user clicks off of WinCombo Row #1 and onto WinCombo Row #2, WinCombo declares a data edit and BindingSource tries to overwrite the values of EF Entity #1 with those of EF Entity #2.
All of that happens BEFORE any kind of validation event is fired, which is scary enough. I have found no programmatic way to prevent the record write.
In the user's mind, no data has been edited. They merely selected a different record. And anyway, when does it EVER make sense to automatically overwrite field values of one row with those of a different row?
I can understand CurrencyManager automatically updating the control's Text and Value properties, but not the properties of the underlying data object associated with the previously selected row.