- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
collection addnew method error
Joined: 04-Mar-2005
I had this line of code in 1.X llbl
Dim jed As VoucherDetailEntity = DirectCast(CurrentVoucherEntity.VoucherDetail.AddNew(), VoucherDetailEntity)
It's broken in 2.0 with the following error:
Cannot format the value to the desired type.
at System.Windows.Forms.Binding.FormatObject(Object value)
at System.Windows.Forms.Binding.PushData(Boolean force)
at System.Windows.Forms.Binding.UpdateIsBinding()
at System.Windows.Forms.CurrencyManager.UpdateIsBinding(Boolean raiseItemChangedEvent)
at System.Windows.Forms.CurrencyManager.UpdateIsBinding()
at System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
at System.ComponentModel.ListChangedEventHandler.Invoke(Object sender, ListChangedEventArgs e)
at SD.LLBLGen.Pro.ORMSupportClasses.EntityViewBase1.OnListChanged(Int32 index, ListChangedType typeOfChange)
at SD.LLBLGen.Pro.ORMSupportClasses.EntityViewBase
1._relatedCollectionListChanged(Object sender, ListChangedEventArgs e)
at SD.LLBLGen.Pro.ORMSupportClasses.CollectionCore1.OnListChanged(Int32 index, ListChangedType typeOfChange)
at SD.LLBLGen.Pro.ORMSupportClasses.CollectionCore
1.PerformAdd(T item)
at SD.LLBLGen.Pro.ORMSupportClasses.CollectionCore1.Add(T item)
at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase
1.AddNew()
at Csi.AccountsPayable.Winforms.VoucherDetailPlusGrid.btnAdd_Click(Object sender, EventArgs e)
at Csi.CsiBaseForms.CsiPlusGridHeaderLLBL.btnPlus_Click(Object sender, EventArgs e) in C:\CSIProjects\CSI\CsiBaseForms\UserControlsLLBL\CsiPlusGridHeaderLLBL.vb:line 141
at System.EventHandler.Invoke(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButtonBase.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButtonBase.PerformClick()
at System.Windows.Forms.Form.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.ContainerControl.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
at System.Windows.Forms.Control.PreProcessMessage(Message& msg)
at System.Windows.Forms.Control.PreProcessControlMessageInternal(Control target, Message& msg)
at System.Windows.Forms.Application.ThreadContext.PreTranslateMessage(MSG& msg)
It breaks on CurrentVoucherEntity.VoucherDetail.AddNew(). If I run that line, I get the same error. I tried changing it to use the collection default view cast to an ibindinglist, but I get the same error. It only errors when there are no records in voucherdetail. If there is an existing record, it works fine. Thanks.
In general, avoid IBindingList methods directly, it's for databinding material. You should use: grab the factory from the collection, call Create() on the factory and then call Add() of the collection. This can all be done through interfaces.
Joined: 04-Mar-2005
is this right? Dim jed As VoucherDetailEntity = DirectCast(CurrentVoucherEntity.VoucherDetail.EntityFactoryToUse.Create, VoucherDetailEntity)
CurrentVoucherEntity.VoucherDetail.Add(jed)
It still produces the error when trying to add the new voucherdetail (jed) to the currentvoucherentity.voucherdetail.add
Thanks
EDIT: Note that a simple addition of an entity blows up also
Dim jed As VoucherDetailEntity = New VoucherDetailEntity CurrentVoucherEntity.VoucherDetail.Add(jed)
EDIT: It's got something to do with binding to the form controls. If I suspend binding it adds fine, and then when resuming binding it blows up. I have heard that binding to null values might do this, but I have all fields set to nullable off now and all fields on the vendordetail entity are set to default's. I double checked and verified this on the jed variable.
Another Edit:
Yet more info It is only on 1 field in the voucher entity. The new entity defaults the value to 0 since it's an int. The combo it's bound to doesn't have a 0 row for it's value property. For some reason, it blows up in 2.0 where it didn't in 1.x.
I can't reproduce it.
Code in test:
[Test]
public void BindCollectionToGridAndAddNew()
{
CustomerEntity customer = new CustomerEntity("CHOPS");
OrderCollection orders = customer.Orders;
ResultsetViewer20 viewer = new ResultsetViewer20();
viewer.BindCollection(orders);
viewer.ShowDialog(null);
}
Code in viewerform:
namespace Unittests.TestLibrary.SqlServerTests.SelfServicing
{
public partial class ResultsetViewer20 : Form
{
private IEntityCollection _boundCollection;
public ResultsetViewer20()
{
InitializeComponent();
}
public void BindView<T>( EntityView<T> toBind )
where T: EntityBase
{
_theGrid.DataSource = toBind;
toBind.ListChanged += new ListChangedEventHandler( OnEntityViewListChanged );
_amountDataSourceTextBox.Text = toBind.Count.ToString();
_amountRelatedCollectionTextBox.Text = toBind.RelatedCollection.Count.ToString();
}
public void BindCollection<T>( EntityCollectionBase<T> toBind )
where T:EntityBase
{
_theGrid.DataSource = toBind;
toBind.ListChanged += new ListChangedEventHandler( OnEntityCollectionListChanged );
_amountDataSourceTextBox.Text = toBind.Count.ToString();
_boundCollection = toBind;
}
void OnEntityCollectionListChanged( object sender, ListChangedEventArgs e )
{
IEntityCollection collection = (IEntityCollection)sender;
_amountDataSourceTextBox.Text = collection.Count.ToString();
}
void OnEntityViewListChanged( object sender, ListChangedEventArgs e )
{
IEntityView view = (IEntityView)sender;
_amountDataSourceTextBox.Text = view.Count.ToString();
_amountRelatedCollectionTextBox.Text = view.RelatedCollection.Count.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
if(_boundCollection != null)
{
IEntity newEntity = _boundCollection.EntityFactoryToUse.Create();
_boundCollection.Add(newEntity);
}
}
}
}
Now, when I click the button, I end up in the button1_Click event handler which perfectly adds a new entity to the collection.
So I'm a little bit puzzled how it breaks your code. The relations I used are 2-way, so Customer -> Order AND order -> Customer are both defined.
Joined: 04-Mar-2005
thanks. I think you'll have to use a new customer also. It works on any entity with children > 0
Only breaks on new entity child add when bound to a combo without the value it's bound to.
Ie the value's in the combo are 1,2,3 and the value of the entity field is 0.
I don't know why, but this worked in 1x but breaks in 2 now. You would think it would break in 1 x also since the combo didn't have the value property.
EDIT. the more i look at it, the less I think it's a combo. It seems to be broken on any control now for a child collection.
The parent binds fine, but when the child collection doesn't have any items in it, it blow up on the first item add.
jspanocsi wrote:
thanks. I think you'll have to use a new customer also. It works on any entity with children > 0
Only breaks on new entity child add when bound to a combo without the value it's bound to. Ie the value's in the combo are 1,2,3 and the value of the entity field is 0.
I don't know why, but this worked in 1x but breaks in 2 now. You would think it would break in 1 x also since the combo didn't have the value property.
EDIT. the more i look at it, the less I think it's a combo. It seems to be broken on any control now for a child collection.
The parent binds fine, but when the child collection doesn't have any items in it, it blow up on the first item add.
Ok, I'll retry with an empty customer and empty orders collection.
(edit) Nope, works here.
[Test]
public void BindCollectionToGridAndAddNew()
{
CustomerEntity customer = new CustomerEntity();
customer.CustomerId = "FOOBA";
OrderCollection orders = customer.Orders;
ResultsetViewer20 viewer = new ResultsetViewer20();
viewer.BindCollection(orders);
viewer.ShowDialog(null);
}
No rows in collection, I then click Add new and it adds a new row. Very strange.
I think I'm not using the same code-setup as you're using, so my test scenario doesn't mimic your situation I think.
Joined: 04-Mar-2005
hmm, it would be very hard to duplicate my setup since there are several layers of inheritance and most of the binding is done on base levels.
The project was started in dot net 1.1, so it uses specific binding stuff from it and not the 2.0 stuff.
Did you bind any controls to the new added entity? I can bind the collection to a grid, but when I bind to individual entities in the child collection, that's when it blows up.
I'm wiring up binding manually with
txtAmount.DataBindings.Add("Value", CurrentVoucherEntity.VoucherDetail, "PostingAmount")
etc.
Thanks
EDIT Seems to be resulting of a couple things. I fixed the combo problem by making the value one that's in the box. Now it's blowing up on a infragistics currency edit trying to set it's value property which is a decimal to a field on the child entity that's also a decimal. Don't know why yet. there is a field on the parent that's the same type of control and it sets fine.
Joined: 04-Mar-2005
OK if I manually go set values for each of the things I'm binding it works.
IE I set jed.postingamount = 0d and then bound it and it worked fine. It's like they aren't being set to defaults in llbl gen even though it shows up as 0d etc in the immediate window.
I can even manuall set the value of the thing I was trying to put in the combo to 0 which doesn't exist and it works then.
I have the feeling we're talking about different things as in: you tried binding with textboxes, I simply added a new entity to a collection bound to a grid (vanilla datagridview control of .net 2.0).
So you're binding the collection to textboxes etc. ? I then have to write a different test, as my test used earlier on simply does a grid binding.
Joined: 04-Mar-2005
yeah, imagine a grid on the form with the child collection bound it it and then as the user clicks each row, the rest of the form gets populated from the row clicked through binding.
Check out my last post though first, as I think I found the problem, just don't know how to fix it.
jspanocsi wrote:
would this have something to do with the currentvalue change you did for 2?
jed.Fields("PostingAmount").CurrentValue returns nothing
That's not right though as it's a standard built in .net type and shoule be 0
That's a change in v2: CurrentValue doesn't contain a default value anymore, that's returned by the property. In v2, CurrentValue contains null if you haven't initialized the field.
Joined: 04-Mar-2005
OK, how do I fix/hack this? Everyone of my forms is broken on this with databinding. You can't bind to a null. I would be forced to intialize every single field. That's not good. The field values are already initialized to their defaults per a parameter in the designer. I would think that the currentvalue would follow this. It's out of sync if it's null and the real property is a 0 etc.
Thanks.
jspanocsi wrote:
OK, how do I fix/hack this? Everyone of my forms is broken on this with databinding. You can't bind to a null. I would be forced to intialize every single field. That's not good. The field values are already initialized to their defaults per a parameter in the designer. I would think that the currentvalue would follow this. It's out of sync if it's null and the real property is a 0 etc. Thanks.
If you bind to a property, e.g. customer.CompanyName, you should get the default value for that field's type, so that shouldn't break. If you use the field's CurrentValue, then it's a different story, but I don;t see how you could bind to that property directly.
Do you bind to a field of the entity?
Also set ConvertNulledReferenceTypesTodefaultValue to FALSE in the project properties. This will make string typed fields to return "" instead of null, when the field is nullable.
Joined: 04-Mar-2005
Otis wrote:
jspanocsi wrote:
OK, how do I fix/hack this? Everyone of my forms is broken on this with databinding. You can't bind to a null. I would be forced to intialize every single field. That's not good. The field values are already initialized to their defaults per a parameter in the designer. I would think that the currentvalue would follow this. It's out of sync if it's null and the real property is a 0 etc. Thanks.
If you bind to a property, e.g. customer.CompanyName, you should get the default value for that field's type, so that shouldn't break. If you use the field's CurrentValue, then it's a different story, but I don;t see how you could bind to that property directly.
Do you bind to a field of the entity?
Also set ConvertNulledReferenceTypesTodefaultValue to FALSE in the project properties. This will make string typed fields to return "" instead of null, when the field is nullable.
For convertnulled property is it true or false? I thought false would leave it null.
I bind straight to the entity property. IE Postingamount. I took a guess that you use currentvalue under the covers to do binding. I just know when currentvalue is nothing, everything blows up. When it's set, it works.
Thanks
jspanocsi wrote:
Otis wrote:
jspanocsi wrote:
OK, how do I fix/hack this? Everyone of my forms is broken on this with databinding. You can't bind to a null. I would be forced to intialize every single field. That's not good. The field values are already initialized to their defaults per a parameter in the designer. I would think that the currentvalue would follow this. It's out of sync if it's null and the real property is a 0 etc. Thanks.
If you bind to a property, e.g. customer.CompanyName, you should get the default value for that field's type, so that shouldn't break. If you use the field's CurrentValue, then it's a different story, but I don;t see how you could bind to that property directly.
Do you bind to a field of the entity?
Also set ConvertNulledReferenceTypesTodefaultValue to FALSE in the project properties. This will make string typed fields to return "" instead of null, when the field is nullable.
For convertnulled property is it true or false? I thought false would leave it null.
Yeah my bad , set it to true if it's false.
I bind straight to the entity property. IE Postingamount. I took a guess that you use currentvalue under the covers to do binding. I just know when currentvalue is nothing, everything blows up. When it's set, it works. Thanks
No if you bind to the property, the property gets read in databinding scenario's and if the currentvalue is null, and it's a valuetype and you have switched off nullable types, you should get the default value, e.g. 0. I'll set up a more appropriate test tomorrow (thursday)
Joined: 04-Mar-2005
thanks. I can definitely reproduce and "fix" it everytime in my app now. Add a new one and just bind and it blows up, set each field to something before binding and it works fine.
as a short term fix, I can add code to a template to generate a method that will "fill" out the entity to default values, but in my opinion, it's a bug. If I set up and want default values from the entity properties, then the current value should match.
I've no idea what the currentvalue has to do with this. databinding doesn't access currentvalue, and neither should you. As databinding gives this error, currentvalue isn't in the picture, you bind against properties.
So to recap what you do and what I thus should test is: - grid with collection which is part of an entity - new entity added to collection - new entity is selected in grid and then shown in textboxes etc. on the form. This is done through databinding and this fails.
Am I correct that this is what you do? You use VS.NET 2005, selfservicing and you have NO nullable typed fields in your entity (i.e.: all fields in your entity, nullable or not, are NOT of type Nullable<T>).
Please check this so I won't test something which isn't your situation, and correct me where I assumed something different. I want to get this solved TODAY so please give me as much information to REPRO this as possible.
Also, if you INITIALIZE an entity somewhere with default values, please explain exactly WHERE you do that.
Ok, again my test works. Please check what I do and if it mimics what you're doing. Probably not as you run in all kinds of problems and I don't see these problems.
First my test, nothing fancy:
[Test]
public void BindCollectionToGridAndAddNew()
{
CustomerEntity customer = new CustomerEntity();
customer.CustomerId = "FOOBA";
OrderCollection orders = customer.Orders;
DataBindingTester viewer = new DataBindingTester();
viewer.BindCollection(orders);
viewer.ShowDialog(null);
}
Then my form. It contains a datagrid v2.0 (thus a datagrid control, not a datagridview control, from the v2.0 assemblies).
It also contains a textbox, which I'll bind to the OrderEntity.EmployeeId field. This is a nullable field, with the type Nullable<int>
namespace Unittests.TestLibrary.SqlServerTests.SelfServicing
{
public partial class DataBindingTester : Form
{
private IEntityCollection _boundCollection;
public DataBindingTester()
{
InitializeComponent();
}
public void BindCollection(IEntityCollection toBind)
{
_boundCollection = toBind;
_employeeTextBox.DataBindings.Add("Text", _boundCollection, "EmployeeId");
_theGrid.DataSource = toBind;
}
private void _addNewButton_Click(object sender, EventArgs e)
{
if(_boundCollection != null)
{
IEntity newEntity = _boundCollection.EntityFactoryToUse.Create();
_boundCollection.Add(newEntity);
}
}
private void _closeButton_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
WHen I click the addnew button, I get a new entity in the collection, and also in the grid. When I select a new entity in the grid I can fill in a value in teh grid and it's then shown in the textbox after I move to the next row, which marks end-edit.
I do see that if I fill in a value in the textbox, the databinding code won't call the setter for orderEntity.EmployeeId (I have a breakpoint on that) while it does when I fill in a value in the grid. This is perhaps due to the nullable type, I'm not sure.
However, this isn't the behavior you're seeing. So I'm a little confused what I have to add to my test to make it repro your situation.
Joined: 04-Mar-2005
Otis wrote:
I've no idea what the currentvalue has to do with this.
databinding doesn't access currentvalue, and neither should you. As databinding gives this error, currentvalue isn't in the picture, you bind against properties.
So to recap what you do and what I thus should test is: - grid with collection which is part of an entity - new entity added to collection - new entity is selected in grid and then shown in textboxes etc. on the form. This is done through databinding and this fails.
Am I correct that this is what you do? You use VS.NET 2005, selfservicing and you have NO nullable typed fields in your entity (i.e.: all fields in your entity, nullable or not, are NOT of type Nullable<T>).
Please check this so I won't test something which isn't your situation, and correct me where I assumed something different. I want to get this solved TODAY so please give me as much information to REPRO this as possible.
Also, if you INITIALIZE an entity somewhere with default values, please explain exactly WHERE you do that.
Thanks for all the effort. I'm not sure what currentvalue has to do with it. Maybe nothing. It was just an observation. When current value is nothing, binding messes up in my project. I've temporarily fixed everything by adding a template to default the values of all properties to their .net default in the constructor of each entity.
"Am I correct that this is what you do? You use VS.NET 2005, selfservicing and you have NO nullable typed fields in your entity (i.e.: all fields in your entity, nullable or not, are NOT of type Nullable<T>). "
This is correct. I also have the property that defaults all values to their .net default on.
"So to recap what you do and what I thus should test is: - grid with collection which is part of an entity - new entity added to collection - new entity is selected in grid and then shown in textboxes etc. on the form. This is done through databinding and this fails. " Yes, this looks correct. Let me explain in detail though just in case. We have a base for with an infragistics 6.2 grid on it. All forms derive from it. In the derived form, we put controls on the form and they interact with the grid at a the base form level abstractly. The user picks a record and it displays on the form. This is the parent record. THIS PART WORKS. Below the controls on the derived form, some forms have a user control which contains more control like textboxes and also another 6.2 grid. When the user picks an item from the upper grid, the lower one is populated with children of the parent. Every time the upper grid is clicked, the lower grid is undatabound with a grd.datsource = nothing and then rebound to the child detail records. This works also. Then the user can click on a lower grid record and more controls get populated with the child detail record. This works also.
What doesn't work is when they click a button on the user control to add a new row to the lower grid. This blows up everytime unless I default all properties of the child record that are going to be bound to controls on the form. It only does this on a brand new collection also. If the child detail section already contains entities, the new works fine.
Here is an example of the code that gets called when the lower grid is bound and unbound as the user clicks new parent records.
Public Sub BindVoucherDetail()
If AppBase.IsRunning = True Then
If CurrentVoucherEntity Is Nothing Then
Return
End If
' grdMain.DataSource = Nothing
grdMain.DataSource = CurrentVoucherEntity.VoucherDetail
' EnableEditControls()
cboAccount.DataBindings.Clear()
txtAmount.DataBindings.Clear()
cboUseTax.DataBindings.Clear()
cboAccount.DataBindings.Add("AccountId", CurrentVoucherEntity.VoucherDetail, "AccountMasterId")
cboAccount.BoundField = "AccountMasterId"
cboAccount.BoundCollection = "VoucherDetailEntity"
txtAmount.DataBindings.Add("Value", CurrentVoucherEntity.VoucherDetail, "PostingAmount")
txtAmount.BoundCollection = "VoucherDetailEntity"
txtAmount.BoundField = "PostingAmount"
cboUseTax.DataBindings.Add("Value", CurrentVoucherEntity.VoucherDetail, "UseTax")
cboUseTax.BoundCollection = "VoucherDetailEntity"
cboUseTax.BoundField = "UseTax"
If TypeOf (Me.ParentForm) Is Csi.CsiBaseForms.CsiBusinessEntryFormBase Then
Dim frm As Csi.CsiBaseForms.CsiBusinessEntryFormBase = DirectCast(Me.ParentForm, Csi.CsiBaseForms.CsiBusinessEntryFormBase)
frm.RegisterCollection(CurrentVoucherEntity.VoucherDetail, "VoucherDetailEntity")
End If
End If
End Sub
This seems to work, as the error is never here.
This is code for the method that get's called when the user clicks the detail add button to add a new detail entity to the parent.
If CurrentVoucherEntity Is Nothing Then Return
Dim col As CollectionClasses.VoucherDetailCollection = CType(grdMain.DataSource, CollectionClasses.VoucherDetailCollection)
If col.Count > 0 Then
If col(0).IsPosted = True Then
'need to enable the amount box on the parent form
Dim frm As EnterEditVouchers = DirectCast(Me.ParentForm, EnterEditVouchers)
frm.curInvoiceAmount.Enabled = True
frm.curInvoiceAmount.IsReadOnlyAlways = False
End If
End If
Dim jed As VoucherDetailEntity = DirectCast(CurrentVoucherEntity.VoucherDetail.EntityFactoryToUse.Create, VoucherDetailEntity)
' jed.AccountMasterId = 0
' jed.PostingAmount = 0D
CurrentVoucherEntity.VoucherDetail.Add(jed)
Dim currencymanagerSys48 As CurrencyManager
currencymanagerSys48 = CType(Me.BindingContext(col), CurrencyManager)
currencymanagerSys48.Position = col.Count - 1
If col.Count = 1 Then
txtAmount.Value = CurrentVoucherEntity.InvoiceAmount
End If
EnableEditControls()
cboAccount.Focus()
If CurrentVoucherEntity.Vendor.IsNew = False Then
jed.AccountMasterId = CurrentVoucherEntity.Vendor.AccountMasterId
End If
'check to see how much balance we have left.
jed.PostingAmount = CalculateOutstandingBalance()
Note the 3 lines
' jed.AccountMasterId = 0 ' jed.PostingAmount = 0D CurrentVoucherEntity.VoucherDetail.Add(jed)
the last of the 3 is where the error is. If I uncomment the other 2, I don't get the error at all and everything works fine. The 2 lines are the 2 fields that are on the form for the children records. It's like the binding to the entity doesn't look at it's properties directly, but some other internal property that's not set yet.
It may be easier if I try to duplicate it and send you a project. I don't know if I can outside our project though. It may take a complex situation to fix it.
Thanks a lot!! Sorry for the long post...
Thanks for the details
As I'm not a VB.NET expert, whats the difference between CType and DirectCast ? You use directcast, I wonder what happens if you use CType instead. (haven't setup a test yet, this was something I noticed.). The fields are all Non-nullable types?
Joined: 04-Mar-2005
yeah, unfortunately i'm stuck in it now.
directcast is basically a (int)somevar in c#. It directly unboxes the variable to an int with no checking. It makes you know what your doing ahead of time where ctype is more like convert.tosomething. It does run time checking etc. ctype is slower. You should use directcast if you know what's boxed in the somevar.
I'll try ctype, but I doubt it will help.
Thanks.
I found this thread: http://channel9.msdn.com/ShowPost.aspx?PostID=166989
It talks about a format event handler, as you get the error in the formatting of the value. Could you check with such a handler what the value is that is about to be formatted? As you're not using nullable types it CAN'T be null. Also set a breakpoint in the property GET clause for the two properties so when they're read you can verify a default value is returned.
Joined: 04-Mar-2005
"Also set a breakpoint in the property GET clause for the two properties so when they're read you can verify a default value is returned. "
I already tried this the other day, and they never get hit. It blows up before that. I'll double check it though.
"It talks about a format event handler, as you get the error in the formatting of the value." I'll do this and get back to you today. After that I'll be out of town until monday though. Thanks for the help.