Excel VBA ListRows.Add Fails

岁酱吖の 提交于 2019-11-29 18:04:15

It appears that what I was trying to do is not possible.

When you develop custom functions, it’s important to understand a key distinction between functions that you call from other VBA procedures and functions that you use in worksheet formulas. Function procedures used in worksheet formulas must be passive. For example, code within a Function procedure cannot manipulate ranges or change things on the worksheet. An example can help make this clear.

You might be tempted to write a custom worksheet function that changes a cell’s formatting. For example, it could be useful to have a formula that uses a custom function to change the color of text in a cell based on the cell’s value. Try as you might, however, such a function is impossible to write. No matter what you do, the function won’t change the worksheet. Remember, a function simply returns a value. It cannot perform actions with objects.

That said, I should point out one notable exception. It is possible to change the text in a cell comment by using a custom VBA function.

Walkenbach, J. (2007). Microsoft Office Excel 2007 Power Programming with VBA. John Wiley & Sons, p 280.

Sorry for the irrelevance to the question, but this is the only StackOverflow post that comes up on Google when searching for similar crash, due to another cause. The crash on ListRows.Add bugged me extensively for quite a while, so sharing the issue which was causing it for me.

There's a table (say MySourceTable) on a worksheet. In my UserForm, a ComboBox's RowSource is a column from this table (MySourceTable[ColName]). On clicking another button on the same UserForm, I was inserting the new row using ListRows.Add into this table and crashing Excel. If this scenario is similar to yours, read on.

The crash is being caused by the ComboBox, which is still attached to the table, and is unable to process the insertion of rows (please mind that it's still instantiated because I'm still on the UserForm when inserting the new row). After a lot of pain, the following lines above and below the insertion solved it for good:

    comboSetSelect.RowSource = ""
    Set newRow = myTable.ListRows.Add
    comboSetSelect.RowSource = "MySourceTable[ColName]" 'col set in properties

This detaches the ComboBox from the table before inserting the new row and once insertion is done, updates the ComboBox again. Further, the newly inserted row's value (if updated right after insertion) shows up as well in ComboBox.

I understand this is a really old question, but it is one that I have come across numerous times while trying to answer for myself. I still do not understand the specifics of why this is happening, but here's my workaround.

Sub AddRow()
     Dim Tbl as ListObject
     Dim MyColumn as Integer

     Tbl.ListRows(1).Range.EntireRow.Insert
     Tbl.ListColumns(MyColumn).DataBodyRange.Cells(1,1).Value = "My Value"
End Sub

By adding a new row above the first existing entry, the table automatically adjusts down as intended, then I can start writing my values into the table.

Again, sorry for reviving an old post, but I was unable to find an adequate solution elsewhere, so this is my own workaround I hoped would be helpful to others in the future.

In my case table was bound by a listbox

 Dim intClientRow As Integer
Dim strLstSource As String
strLstSource = frmHNW.lstB01People_List.RowSource
frmHNW.lstB01People_List.RowSource = ""
intClientRow = UpdateTableFromFrame(frmHNW.fraB01People, "Clients_tblClientDetails", True)
If intClientRow > 0 Then
    UpdateTableFromList frmHNW.lstB01Contact_Method, "ClientPeople_tblClientContactMethod", "=getClientID(" & intClientRow & ")"
    UpdateTableFromList frmHNW.lstB01Pref_Days, "ClientPeople_tblClientPrefDay", "=getClientID(" & intClientRow & ")"
    UpdateTableFromList frmHNW.lstB01Pref_Time, "ClientPeople_tblClientPrefTime", "=getClientID(" & intClientRow & ")"
End If

frmHNW.lstB01People_List.RowSource = strLstSource

UpdateTableFromFrame forms applies lisrows.add method to the source table of the listbox. After hours of testing I found that when I don't remove the list source my listrows.add method fails. So I removed rowsource of the listbox before calling UpdateTableFromFrame and restored back once row addtion is done. This solved the problem

This also bugged me for a while. For me, it seemed that calling ListRows.Add multiple times in a loop - caused this error to occur, and sometimes crashed Excel. The solution that worked for me: I added DoEvents command after the ListRows.Add command:

tbl.ListRows.Add
DoEvents

I know this is an old thread, I don't want to re-post and I beleive I have a solution that might help others.

Quick bit of info about my scripts, I have ListRows.Add in Private Sub BTN_Save_DblClick I removed all my code and left only this module, this to my surprise worked, so I started implementing each sub and function until I got to the one that was causing the problem.

It turns out that (for me) because I had UserForm_Initialize() as a Private Sub instead of a Public Sub, this caused ListRows to fail, crashing excel in the process..

So if you are having this issue, and you have UserForm_Initialize(), make sure it is set to Public instead of private.

Anyway if that doesn't work, then it's a simple process of elimination, remove all your code except the one with ListRows and add each sub/function testing each time, until you find the one that's causing the problem.

Hope this helps.

EDIT So this was a temporary fix, it started crashing again, so I removed the line of code within the userform_initialize and it fixed it again.. this is so strange because all it does is ComboBox1.RowSource=NamedRange.

I never had this sort of issue with Excel VBA before.

Another cause for ListObject.ListRows.Add to fail can be worksheet protection. Since I didn't see this mentioned in any of my search results, I'd like to add it here for future reference.

If a worksheet has been protected with

worksheet.Protect 

be sure to

worksheet.Unprotect 

it before applying ListObject.ListRows.Add!

In short

tab_.ListRows(1).Range.EntireRow.Insert may(!) work instead of tab_.ListRows.Add.
(Like already suggested in SandPiper's answer)

encapsulating it in a more general function that also returns ListRow:

Function TabRowAdd(tab_ As ListObject) As ListRow
    tab_.ListRows(1).Range.EntireRow.Insert
    Set TabRowAdd = tab_.ListRows(1)
End Function

you would use it like this: TabRowAdd(tab_) instead of tab_.ListRows.Add

Possible Cause

If there are other non-table cells underneath (or maybe even beneath) the current table, it wont work, because (I guess) the "shifting-down" of this other content could cause bad side-effects or could be more complicated.

So e.g. imagine the following table layout and how should the insert of a row in table 1 be accomplished straight-forward? (generally bad/stupid layout - I know :) )

| table 1 header |  | table 2 header |
|         row 1  |  |         row 1  |
|         row 2  |  |         row 2  |         
                    |         row 3  |  | table 5 header |
| table 3 header |  |         row 4  |  |         row 1  |
|         row 1  |                      |         row 2  |
|         row 2  |                      |         row 3  |
                                        |         row 4  |
    | table 4 header      |             |         row 5  |
    |         row 1       |

=> this is not easy and that's why I guess they may just check, if there is non-table stuff beneath or underneath the to-be-manipulated (insert row/col, delete row/col) table and thus throw some 1004 exception.
(maybe even following "non-A-column-starting" tables would have that problem already - I did not check it)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!