Ok, has anybody seen this. Infragistics.Excel.Workbook.Load() throws System.ArgumentException: An item with the same key has already been added
Here is what I am doing. I am giving the user the option of exporting the ultraWinGrid data to an existing excel workbook. Here is my method so far:
method public void exportToExcel( ):
define variable lResponse as logical no-undo.
define variable objWorkBook as Infragistics.Excel.Workbook no-undo.
define variable objWorkSheet as Infragistics.Excel.Worksheet no-undo.
define variable filePath as character no-undo.
define variable tabName as character no-undo.
message "Export to existing workbook?"
view-as alert-box question buttons yes-no
update lResponse.
if lResponse = true then
do:
filePath = getFilePath().
objWorkBook = new Infragistics.Excel.Workbook().
objWorkBook = Infragistics.Excel.Workbook:Load(filePath).
message "Create a new worksheet?"
view-as alert-box question buttons yes-no
update lResponse.
if lResponse = true then
do:
getTabName(output tabName).
objWorkSheet = objWorkBook:Worksheets:Add(tabName).
orderListExcelExporter:Export(grdOrderList, objWorkSheet).
objWorkBook:Save(filePath).
end.
end.
if valid-object(objWorkBook) then
delete object objWorkBook no-error.
if valid-object(objWorkSheet) then
delete object objWorkSheet no-error.
end method.
Nowl, it works great the first time I open the xls file but if I try re-running the application and calling the same file, I get the error at the point of loading the file. I'm not sure if I'm missing something again and I haven't found anything on Infragistics' site to help yet.
You could also just use the UltraGridExporter component. Then all you'd need to do is something like:
Incidentally, you can probably not do the explicit DELETE OBJECT calls at the end of the method - the GC will take care of them, since the variables are scoped to the method.
-- peter
Are you suggesting it is bad to take out one's own trash?
Are you suggesting it is bad to take out one's own
trash?
Trash should always be taken out. I'm just saying that if someone else is going to do it for you, why do it yourself?
-- peter
Because, if you do it yourself, then you know when it happens. To me, automated garbage collection is for lazy programmers and as insurance at having missed something. I will still program according to the "if you make it, you delete it" rule.
Because, if you do it yourself, then you know when it
happens. To me, automated garbage collection is for
lazy programmers and as insurance at having missed
Without wanting to get into a protracted discussion about the merits or otherwise of lazy programmers - although I think that's overall a good thing - a lack of DELETE OBJECTS to me makes the code far more readable.
I will still program according to the "if
you make it, you delete it" rule.
Fair enough. And it's certainly not going to break anything if you do that.
-- peter
a lack of DELETE OBJECTS to me makes the code far more readable.
Whereas I would suggest the reverse. To me, NEW and DELETE OBJECT fulfill much the same role as DO and END to bracket the lifecycle of the object. Without the DELETE, you are left guessing as to whether one is done with it or not.
Whereas I would suggest the reverse. To me, NEW and
DELETE OBJECT fulfill much the same role as DO and
END to bracket the lifecycle of the object. Without
the DELETE, you are left guessing as to whether one
is done with it or not.
Not if you know the GC has taken care of it.
I see your point though - you can run ProLint on your code to ensure the NEW and DELETE statements match. That becomes more complex when you use (say) Factories for creation, or when you use DYNAMIC-NEW(), or when you invoke the object in one place and delete it in another, but it's still feasible, I'd think.
Of course, if you've forgotten to explicitly DELETE one of a hundred object, GC will take care of it, and you may be none the wiser.
The readability issue is illustrated for me by the code generated by the Visual Designer. Before GC, it used to be that the object's destructor had to explicitly delete each member; in addition, InitializeComponent uses a bunch of temporary objects which also needed to be manually deleted. The p-code was massive(r), even in mildly complex Forms. I should also note that trying to figure out what was going on in the destructor was no fun at all.
-- peter
Not if you know the GC has taken care of it.
You know that it will go away, but not when it is gone.
In fact, I'd like an event on GC so that I could optionally log when it cleaned something up for me in order to go back to the code and figure out why I hadn't cleaned it up.
The readability issue is illustrated for me by the code generated by the Visual Designer.
"Readability" and "Visual Designer" are not necessarily two things that belong in the same sentence.
Not if you know the GC has taken care of it.
You know that it will go away, but not when it is
gone.
This is not unique to the ABL's GC.
How important is it to you that you know when the GC removes the object?
In fact, I'd like an event on GC so that I could
optionally log when it cleaned something up for me in
order to go back to the code and figure out why I
hadn't cleaned it up.
Surely this is a function for the debugger, or at development time?
-- peter
Well, I can say that habit of deleting my own objects started when I was still in school. Although I haven't written anything in C++ in about 6-plus years that's where it became a habit.
As far as my error. The reason I am using the Workbook object is to allow the user the opportunity to export their data into an existing spreadsheet. Please bare in mind that the method isn't complete, just testing it a piece at a time. I REALLY want to get away from using Interop at all so that's why I'm trying with the Infragistics objects.
I am enjoying this nice debate though. Thanks
Not if you know the GC has taken care of it.
You know that it will go away, but not when it is
gone.
Well you still have the client log file indicating when the GC cleaned up an object.