I have an excel template which is filled by added sheets that I receive from colleagues.
Each sheet that I receive contains about 12 named ranges which do all have the same names. Each name begins with "flags".
I found another question on stackoverflow that gives a solution to delete name ranges with names that are not equal to given names:
loop through names and delete those not matching specified pattern
I used this solution to create my own code.
The names I want to delete (because they make my file awfully slow) all start with "flags".
I therefore used the
left(myname.namelocal, 5)
function to find each name in my workbook which starts with "flags" and have it deleted.
However, this code does not work. The names are not deleted when I execute the code.
And I do not understand why it does not work. I have tried a similar code on a small file to test the code. It worked fine.
The only difference is that the test file was not password protected. That is what I added to the code to make sure the code can delete the names.
Sub deletenames()
'verwijderd alle naam-bereiken waarvan de naam begint met flags uit het verwerkingsbestand.
Dim ws As Worksheet
Dim myName As Name
For Each ws In ThisWorkbook.Worksheets
ws.Unprotect ("TM")
Next ws
For Each myName In ThisWorkbook.Names
If Left(myName.NameLocal, 5) = "flags" Then myName.Delete
Next
End Sub
what can I do to make this code work?
The problem is most likely that Excel allows both sheet-specific and workbook-wide named ranges. Since you've mentioned that all sheets are copied together, I suspect that named ranges are associated with sheets.
Edit:
The sheet-specific named ranges have a name Sheet!Range, and thus your check must consider the sheet prefix. A solution as in your comment to compare the name with Like is ok:
If myName.NameLocal Like "*!flags*" Then myName.Delete
Related
I have inherited an Excel workbook with several worksheets, all with named tabs. I have some VBA code that runs depending on buttons and inputs. When I compare the VBAProject and the list of Excel Objects, the sheet's names match the tabs. All good so far.
However, within the VBA code and on the spreadsheets itself, it refers to other worksheets. They are still part of the workbook, and I think that the code was created, and then tabs were renamed. But I don't know how Excel keeps the connection, or, more importantly, how I am supposed to figure out the connections.
So, for instance, I have a VLOOKUP that refers to MiscDataRange
=IF((VLOOKUP(E4,MiscDataRange,4,0))="Y"...
I don't know what MiscDataRange is, but within the VBA code I find one reference. Right after specifying worksheet "Misc Interrupt", which is NOT any of the named tabs.
Worksheets("Misc Interrupt").Range("H2:H47") = "N" 'Reset to N at noon.
UpdateData
Range("MiscDataRange").ClearContents
I do have a sheet called MiscInt, and it appears to be the sheet that "Misc Interrupt" is using and MiscDataRange is referencing.
My problem is there is a hole in my knowledge - I can guess that MiscInt and Misc Interrupt are the same worksheet, that the VLookup is referring to data on the MiscInt sheet. But I am reduced to guessing. I cannot find anything in the file that maps those two as the same. Where would I look to find that?
This question seems related, except he simply has a VLookup, and isn't looking at the VBA code: Non-existent Excel Worksheet, but Formulas and Defined names still work?. In addition, from the VBA code, I can see hidden and visible worksheets.
You can open the Names manager by going to the Formula Tab and clicking Names Manager or pressing ctrl+F3 or you can paste a list of Names and what the names reference by pressing F3. It may be necessary to unhide the names first.
Sub ShowAllNames()
Dim n As Name
For Each n In ThisWorkbook.Names
n.Visible = True
Next
End Sub
If I understand your question, you're looking to find where those named ranges are.
You can use a sub like this:
Sub t()
Debug.Print "Sheet: " & Range("testNamedRange").Parent.Name
Debug.Print "Full Location: " & Range("testnamedrange").Name
Debug.Print "File path: " & Range("testnamedrange").Worksheet.Parent.Path
End Sub
Does that help?
First question, excuse me if this has already been solved, but I've searched thoroughly and cannot find an answer:
I have linked several named ranges into a word document. This word doc (and the related excel workbook with named ranges) is a template: it's for a coworker who will make many copies of these templates (of both the word doc and the excel workbook).
I would like to include a command button in the word doc that, when clicked, will update the sources for the linked named ranges. Specifically, I want it to set the workbook with the same name as the worddoc, as the source.
The issue is that it does not like the named range I have entered. I get the:
Run-time error '6083': Objects in this document contain links to files that cannot be found. The linked information will not be updated.`
However, I have quadrupled-checked my excel doc, the named range exists. AND, when I hit Alt+F9 in word, I clearly see the link contains the named range!
{LINK Excel.Sheet.8 C:\Users\Marc\Documents\WIP_SSS.xlsm CED \a \p}
Here is my code:
Public Sub ChangeSource()
Dim filename As Variant
Dim fieldcount As Integer
Dim x As Integer
filename = Left(Application.ActiveDocument.Name, Len(Application.ActiveDocument.Name) - 4) & "xlsm"
fieldcount = ActiveDocument.Fields.Count
For x = 1 To fieldcount
'Debug.Print ActiveDocument.Fields(x).Type
If ActiveDocument.Fields(x).Type = 56 Then
ActiveDocument.Fields(x).LinkFormat.SourceFullName = ActiveDocument.Path & "\" & _
filename & "!CED"
End If
Next x
End Sub
If I don't enter the named range at all, the macro works, but it embeds the entire excel worksheet (which I do not want it to do). Any ideas on how/ why it is not liking the named range?
Thanks,
Marc
UPDATE:
With help from Bibadia, I found a solution; in addition, I want to document some strange behavior exhibited by Word VBA:
First off, the solution code:
Public Sub ChangeSource()
Dim filename As Variant
Dim fieldcount As Integer
Dim x As Integer
filename = ThisDocument.Path & "\" & Left(Application.ActiveDocument.Name, Len(Application.ActiveDocument.Name) - 4) & "xlsm"
fieldcount = ActiveDocument.Fields.Count
For x = 1 To fieldcount
On Error Resume Next
If ActiveDocument.Fields(x).Type = 56 Then
ActiveDocument.Fields(x).Delete
End If
Next x
ActiveDocument.Bookmarks("R1").Range.InlineShapes.AddOLEObject filename:=filename & "!Range1", LinkToFile:=True
End Sub
I first deleted all type 56 fields (linked object, or more technically, "wdfieldlinked"). Then, I added OLEObjects at pre-set bookmark locations.
Interestingly, just as Bibadia noted, the key was to input the LinkToFile:=True code. It seems Word will not accept the object if it is embedded: if I remove that line, I get the error Word Cannot obtain the data for the C:\...\document!NamedRange link.
Finally, I found one other odd behavior: When trying to simply replace the link, using this code,
ActiveDocument.Fields(1).LinkFormat.SourceFullName = filepath+name & _
"!CED" 'that is the named range
it would work once, when I changed both the word document's and the excel workbook's filenames (see original message for context). So, when the new filepath+name DID NOT match the existing filepath+name, Word VBA accepted the change. However, once initially updated, if I tried to run the macro again, I would get:
run-time error '6083': Objects in this document contain links to files that cannot be found. The linked information will not be updated.
I would get this error even if I changed the named range to another named range in the same worksheet (and obviously same workbook). So it appears that Word VBA does not like "updating" filepath+name when the filepath+name does not change.
Just so anyone who didn't know (like me) now knows. Sorry for the long update, I just wanted to be thorough.
I am not completely sure of this, but it is a little too long for a comment.
As far as I know, you can only set LinkFormat.FullSourceName to the name of a file, not a fullname + subset name, which is what you are trying to do when appending the "!CED". Although you can read the subset name (CED) from OleFormat.Label, you can't modify it as it's a read-only property.
So if you actually need to modify the subset name (CED), AFAICS the only way to do it is to delete and reinsert the LINK field. If you reinsert using Fields.Add, you just specify the text of the field, so you can get the file name and Subset name right. What is slightly confusing is that if you insert a LINK using InlineShapes.AddOleObject, you can specify fullname+subset name in exactly the way that you are trying to do in your code.
However, I do not think you are trying to modify the Subset name. So let's assume that you already have a LINK field along the lines of
{ LINK Excel.SheetMacroEnabled.12 "the full pathname of a .xlsm file" CED \a f 0 \p }
Word will only be able to update that link if the path+filename is valid (i.e. there's a .xlsm at that location, the workbook has a Range Name called CED, and the Range Name is in the first Sheet. Otherwise, you have to specify a Sheet name as well, e.g.
{ LINK Excel.SheetMacroEnabled.12 "the full pathname of a .xlsm file" Sheet2!CED \a f 0 \p }
It's just a guess, but if your code is trying to connect to a Workbook where the range defined by CED is not in the first sheet, you would see the error you describe.
Further, the scope of the CED Range Name has to be either "workbook" or the name of the first sheet. Otherwise, if the scope is the first sheet but the range is actually in another sheet, or vice versa, I do not think Word can make the connection whatever subset name you provide (my guess is that Word never really caught up with Excel after Excel introduced multi-sheet workbooks).
If CED can reference sheets other than the first one, I think you will probably have to use the Excel object model to discover which sheet its Range is in, construct the appropriate Subset name, and delete/re-insert the LINK field.
I run a spreadsheet report that holds about 50 columns of data for anywhere from 1 to 5000 rows. I'm only interested in 4 columns, but they are never in the same location as these reports are set-up a bit differently for each client. I then take those 4 columns and paste into a new workbook that I can import into another program.
I have three macros created that accomplish this task flawlessy if ran from the local file. When I load them into the personal.xls for use on various files I have issues. Specifically workbook/worksheet referencing issues.
Parts of the macro run to the sheet I intend from them to result on, while other parts act on the personal.xls file itself. This confuses me because I don't have any lines that use commands such as 'thisworkbook' or 'activeworksheet'.
For example:
- The first line is coded to rename Sheet1. The macro renames Sheet1 in personal.xls.
- The next line is the first of four Find commands that locate where the columns i'm interested are located and then move them. This macro runs perfectly on the sheet I intend.
I think my best course is to begin each macro by naming the active workbook and then breaking out each command to the workbook level instead of starting with Worksheets, Range, etc.
Can anyone help me understand what VBA is thinking when performing macros from personal.xls and how to best avoid the macros being run on that sheet itself?
There are two approaches you can take. I use one or both in my code - it's not a one or the other situations.
Declare Variables
Start by defining each sheet that you want to work on in a variable. I generally stay at the sheet level, but that's just a personal choice. If you'd rather be at the workbook level, that's OK too. A procedure might looks like:
Dim shSource as Worksheet
Dim shDest as Worksheet
Set shSource = Workbooks("SomeBook").Worksheets(1)
Set shDest = ActiveWorkbook.Worksheets("Summary")
then whenever I reference a Range or Cells or anything else on a sheet, I preface it with that sheet object variable. Even if I need to get to the workbook, I start with the sheet. If I needed to, for instance, close the Source workbook from the above example, I would use
shSource.Parent.Close False
I set up the sheet variables I need and then everything I do is in terms of those variables.
Edit
If you're opening or creating workbooks, then variables is definitely the way to go. For example, if you're opening a workbook, you could use one of these two examples
Dim wb As Workbook
Set wb = Workbooks.Open(C:\...)
Dim ws As Worksheet
Set ws = Workbooks.Open("C:\...).Worksheets(1)
or creating new, one of these two examples:
Dim wb As Workbook
Set wb = Workbooks.Add
Dim ws as Worksheet
Set ws = Workbooks.Add.Worksheets(1)
With Blocks
When I'm only trying to get at something one time, it seems like a waste to set up a bunch of variables. In those cases, I use a With Block so I can still have fully qualified references, but without a bunch of clutter in my code.
With Workbook("MyBook")
With .Worksheets("First_Sheet")
.Range("A1").Value = "stuff"
End With
With .Worksheets("Second_Sheet")
.Range("G10").Formula = "=A1"
End With
End With
I probably prefer the variable method, but I use them both.
Edit 2: Implicit Referencing
You should always explicitly reference your workbooks and worksheets, but it's still instructional to know how Excel will behave if you don't. A line of code that starts like Range("A1").Value = ... is called an unqualified reference. You're referencing a range, but you're not saying which sheet its on or which workbook that sheet is in. Excel handles unqualified references differently depending on where your code is.
In a Sheet's Class Module (like where you use sheet events like SelectionChange), unqualified references refer to the sheet represented by that module. If you're in the Sheet1 module working in the Change event and you code x = Range("G1").Value then the G1 you are referring to is on Sheet1. In this case, you should be using the Me keyword rather than relying on Excel.
In any other module (like a Standard Module), unqualified references refer to the ActiveSheet. The same x = Range("G1").Value code in a Standard Module refers to G1 on whichever sheet has the focus.
Excel's treatment of unqualified references is very reliable. You could easily create robust code by relying on Excel to resolve the qualified references. But you shouldn't. Your code will be more readable and easier to debug if you qualify every reference. I qualify every reference. And that's not one of those things I "always" do except when I'm lazy - I really do it 100% of the time.
I have a code that copies all sheets from book 1 to book 2. It copies the sheets several times, so I change the names by adding 001_, 002_ and etc in front of the copied sheets names. All of the sheets have dropdown menues. The problem is that they are referenced (Formulas--> Name Manager) to the previous workbook and they are not working.
There are 5 sheets to be copied and 4 of them are taking the values for the dropdown menues from the sheet TypeLists. This sheet is copied only once, so the code doesn't copy it, if it is already present in Book 2.
Using Record Macro, in changing one of the references, I got this:
ActiveWorkbook.Worksheets("003_TDT").Names("List_DataType").RefersToR1C1 = _
"=TypeLists!R3C14:R5C14"
What I did is, I went to Formulas --> Name Manager and changed one of the references from:
='C:\Users\z183464\Desktop[seq_tdt_template.xlsx]TypeLists'!$N$3:$N$5
to:
=TypeLists!$N$3:$N$5
My question is: How can I write a Macro that changes all the references from Book1/TypeLists to Book2/TypeLists ?
Cheers!
You can use this code. It iterates through all the defined names and changes its reference to the same value with the undesired part extracted (replaced by "").
This is not a macro, but VBA. You need to insert it in the VBA editor (Alt+F11).
Sub replaceNameValues()
Dim oName As Excel.Name
For Each oName In ThisWorkbook.Names
oName.RefersTo = Replace(oName.RefersTo, "C:\Users\z183464\Desktop[seq_tdt_template.xlsx]", "")
Next
End Sub
Regards,
This seems like such a simple question, but I can't seem to find a good way to do it. I want to check if the name of an Excel Worksheet with an index of 'n' is not in the original set of worksheet names of my VSTO workbook.
The workbook has 13 worksheets in the template and the program adds more sheets to the end and sometimes the middle. Any sheet added wouldn't be named one of the sheet names included in the template (I've successfully blocked this). I often want to take actions to all the sheets added that are not of the orginal 13, so I had hoped to try and use an array, or the list ThisWorkbook.Names as it exists from the initial template.
Right now my work around is:
If ThisWorkbook.Worksheets(n).Name <> Sheet1.Name OrElse ThisWorkbook.Worksheets(n).Name <> wbX.Sheet2.Name ..... <>wbX.Sheet13.Name
Needless to say this is cumbersome. Am I even thinking about this the right way, or is there an easier way to check if a name is not in the original sheet names?
I know that if I could force all the sheets after 13 I could just use the index, but at the moment that's not feasible for the intention of the project.
At startup fill all worksheetnames from the template into a List:
Dim templateSheets As List(Of String) = new List(Of String)
For Each sheet As Excel.Worksheet in Globals.ThisWorkbook.Worksheets
templateSheets.Add(sheet.Name)
Next
Then your above query can get abbreviated to
If Not templateSheets.Contains(ThisWorkbook.Worksheets(n).Name) Then