Save userform data

S

SoCal Rick

Hi,
I have a userform with a lot of data (text boxes, check boxes, option
buttons). When the doc file is saved, these values are lost. Is there any
way to include a subroutine that would save these values to a txt file
(without using doc form fields) and allow the information to be retrieved
when the doc is reopened?
For example: the userform asks for the "Name". On the clicking of a
command button, the active document form field "Name" is set to equal the
userform "Name". However, some of the saves are much more complicated. A
check box could result in a form field being set to the a paragraph in the
code. I don't want to save the paragrahp in the txt file. I want to save
the userform check box value.
Any ideas?
Thank you,
SoCal Rick
 
G

Gordon Bentley-Mix

Rick,

I don't know that you need to use a separate text file to save the data; I
do something very similar (to provide the ability for users to rerun a
template without having to re-enter everything) using document variables. And
I do some pretty complex stuff this way.

For example, I have a template that allows a user to collect multiple
instances of similar information (names and addresses of parties to a
contract). This information is loaded into an array when it's initially
collected, so saving this information and re-displaying it when rerunning the
template can be quite involved. I'll post some code below to give you an idea
of how I do this, but first just a quick comment on something else you
mentioned.

You said:
"A check box could result in a form field being set to a paragraph in the
code."

Whenever possible, I try to avoid writing large blocks of text into a
document using code; formatting can be a nightmare, and Word is a much better
text editor. ;-P What I usually do is either: wrap a bookmark around some
existing text in the template and then hide or show the text depending on the
value in the UserForm; or, set a bookmark at the proper location and then
insert an AutoText entry at the point identified by the bookmark. Note that
in the second case, I make sure that my AutoText entry includes the same
bookmark as the one that I'm using to identify when to insert the AutoText.
This way the bookmark is "retained" so the template can be rerun.

Before getting into using document variables for saving and re-displaying
values, a bit of explanation on how I work.

Generally, I try to avoid using the ActiveDocument object. Instead, I create
a Document object and set this object to the ActiveDocument then refer to
this object explicitly in my code. That way I don't end up accidentally doing
something to the wrong document. Accordingly, you'll see references to
"MyDoc" throughout my code.

I also follow the same basic rule with UserForms: create a UserForm object
and set it to a specific instance of a particular UserForm. Thus, you may see
references to "MyForm" or "Me" in my code.

Finally, I try to keep the document-related operations separate from the
UserForm-related operations. This means that I have a separate "main" module,
which includes all of the "document ops" code, as well as code for creating
and displaying the UserForm. Then when I click the 'OK' button on a UserForm,
I collect most of the UserForm values in various variables in the main module
and then work with the values from these variables when creating my document.
The most notable exception is the "parties to the contract" array I discussed
above. In this case, I use a Public array because creating a large number of
variables on the fly is just too much work, and the Public array is easy
enough to work with in this limited application.

Now on to the code.

First, because the "mechanics" of saving a value in a variable is the same
regardless of what the value might be, I write a standard procedure that
accepts arguments, like this:

Sub SaveVarValue(VarName As String, ByVal VarVal As String)
With myDoc
If fcnFindVar(VarName) = False Then .Variables.Add VarName
With .Variables(VarName)
If VarVal <> "" Then .Value = VarVal Else .Value = " "
End With
End With
End Sub

This procedure uses a Boolean function (that also accepts arguments) to
determine if the variable exists before trying to write into it and creates
it if it's not there. I also use this function when retrieving saved values,
which is why it's declared as Public.

Public Function fcnFindVar(VarName As String) As Boolean
Dim myVar As Variable
fcnFindVar = False
For Each myVar In myDoc.Variables
If myVar.Name = VarName Then
fcnFindVar = True
Exit For
End If
Next myVar
End Function

An example of the above procedure in use:

Private Sub SaveGoodsVars()
SaveVarValue "GoodsTypeIdx", GoodsTypeIdx
SaveVarValue "NewUsedOption", NewUsedOption
SaveVarValue "AttachedScheduleChk", CStr(bAttachedScheduleChk)
SaveVarValue "GoodsField1", GoodsField1
SaveVarValue "GoodsField2", GoodsField2
SaveVarValue "GoodsField3", GoodsField3
SaveVarValue "GoodsDescription", GoodsDescription
End Sub

And an explanation of the same: 'GoodsTypeIdx' is an Integer variable that
records the ListIndex of a ComboBox control. 'NewUsedOption' is a String
variable that records which of two OptionButton controls is selected.
'bAttachedScheduleChk' is a Boolean variable that records the state of a
CheckBox control. (I convert it to a String because document variables don't
accept Boolean values.) The remainder are String variables that hold the
values from various TextBox controls.

As discussed above, these values are collected in the Click event of the
'OK' button in the UserForm, as follows:

Private Sub CollectGoodsDetails()
With myLAForm
GoodsTypeIdx = .cboGoodsType.ListIndex
Select Case True
Case .optNewGoods.Value
NewUsedOption = "New Goods"
Case .optUsedGoods.Value
NewUsedOption = "Used Goods"
End Select
GoodsField1 = .txtGoodsFld1.Value
GoodsField2 = .txtGoodsFld2.Value
GoodsField3 = .txtGoodsFld3.Value
GoodsDescription = .txtGoodsDescr.Value
bAttachedScheduleChk = CBool(.chkAttachedSchedule.Value)
End With
End Sub

Another example of how I save values from my "parties" array:

Private Sub SaveCustomerVars()
Dim i As Integer
Dim CustomerNameVar As String
Dim CustomerAddressL1Var As String
Dim CustomerAddressL2Var As String
Dim CustomerTypeVar As String
For i = 1 To CustomerCount
CustomerNameVar = "CustomerName" & i
SaveVarValue CustomerNameVar, CustomersArray(0, i)
CustomerAddressL1Var = "CustomerAddressL1" & i
SaveVarValue CustomerAddressL1Var, CustomersArray(1, i)
CustomerAddressL2Var = "CustomerAddressL2" & i
SaveVarValue CustomerAddressL2Var, CustomersArray(2, i)
CustomerTypeVar = "CustomerType" & i
SaveVarValue CustomerTypeVar, CustomersArray(3, i)
Next i
End Sub

Again, the values in 'CustomersArray' are all Strings, and the 'For...Next'
loop just loops through the array, creates document variable names for each
array value and saves the value into the appropriate doc var, which do get
created on the fly. (Note that if I'm rerunning the template, I delete all of
the old "parties" doc vars first before saving the new ones. This works very
similar to the above but uses a procedure that deletes the doc vars instead
of creating them.) Since it's a Public array, I don't have to worry about
collecting the values.

The "re-use" side is a bit more complex, but I'll try to show you the
relationship what I used above to describe the save process and the code in
the UserForm_Initialize event.

As is the case with saving the doc vars, the process for retrieving the
values is basically the same regardless of the variable involved. However,
depending on the property of the control that I'm trying to set with the doc
var, I have to use slightly different functions.

For retrieving a String (e.g. the Value of a TextBox):

Function fcnLoadVarTextValue(VarName As String) As String
Dim Temp As String
With myDoc
If fcnFindVar(VarName) Then
With .Variables(VarName)
If .Value <> " " Then Temp = .Value Else Temp = ""
End With
Else: Temp = ""
End If
End With
fcnLoadVarTextValue = Temp
End Function

For retrieving an Integer (e.g. the ListIndex of a ComboBox):

Function fcnLoadVarNumberValue(VarName As String) As Integer
Dim Temp As Integer
With myDoc
If fcnFindVar(VarName) Then
With .Variables(VarName)
If .Value <> " " Then
If IsNumeric(.Value) Then Temp = .Value Else Temp = 0
Else: Temp = 0
End If
End With
Else: Temp = 0
End If
End With
fcnLoadVarNumberValue = Temp
End Function

For retrieving a "Boolean" (e.g. the state of a CheckBox):

Function fcnLoadVarBoolValue(VarName As String) As Boolean
Dim bTemp As Boolean
With myDoc
If fcnFindVar(VarName) Then
With .Variables(VarName)
If .Value <> " " Then
Select Case .Value
Case "True"
bTemp = True
Case Else
bTemp = False
End Select
Else: bTemp = False
End If
End With
Else: bTemp = False
End If
End With
fcnLoadVarBoolValue = bTemp
End Function

And the above in action in the Initialize event:

Private Sub LoadGoodsVars()
cboGoodsType.ListIndex = fcnLoadVarNumberValue("GoodsTypeIdx")
If fcnFindVar("NewUsedOption") Then
Select Case myDoc.Variables("NewUsedOption").Value
Case "New Goods"
optNewGoods.Value = True
Case Else
optUsedGoods.Value = True
End Select
Else: optNewGoods.Value = True
End If
txtGoodsFld1.Value = fcnLoadVarTextValue("GoodsField1")
txtGoodsFld2.Value = fcnLoadVarTextValue("GoodsField2")
txtGoodsFld3.Value = fcnLoadVarTextValue("GoodsField3")
txtGoodsDescr.Value = fcnLoadVarTextValue("GoodsDescription")
chkAttachedSchedule.Value = fcnLoadVarBoolValue("AttachedScheduleChk")
End Sub

(Note that OptionButtons don't lend themselves to using a function very
well, although I could probably do something with my Boolean function to set
the status of each OptionButton individually. Of course then I'd have to
store this information in separate doc vars... more work than it's worth
IMHO.)

And finally, the process for rebuilding the "parties" array:

Private Sub LoadCustomerVars()
Dim i As Integer
Dim CustomerNameVar As String
Dim CustomerAddressL1Var As String
Dim CustomerAddressL2Var As String
Dim CustomerTypeVar As String
ReDim CustomersArray(3, 1 To CustomerCount)
For i = 1 To CustomerCount
CustomerNameVar = "CustomerName" & i
CustomersArray(0, i) = fcnLoadVarTextValue(CustomerNameVar)
CustomerAddressL1Var = "CustomerAddressL1" & i
CustomersArray(1, i) = fcnLoadVarTextValue(CustomerAddressL1Var)
CustomerAddressL2Var = "CustomerAddressL2" & i
CustomersArray(2, i) = fcnLoadVarTextValue(CustomerAddressL2Var)
CustomerTypeVar = "CustomerType" & i
CustomersArray(3, i) = fcnLoadVarTextValue(CustomerTypeVar)
If i = CustomerCount Then
Select Case CustomersArray(3, i)
Case "I"
optCustomerIndividual.Value = True
Case "T"
optCustomerTrust.Value = True
Case Else
optCustomerCompany.Value = True
End Select
End If
Next i
LoadCustomersList
End Sub

As well as the process for displaying the array values for the "Name" and
"Type" in a ListBox:

Private Sub LoadCustomersList()
Dim n As Integer
With lstCustomers
.Clear
If CustomerCount > 0 Then
For n = 1 To CustomerCount
.AddItem CustomersArray(0, n)
.List(n - 1, 1) = CustomersArray(3, n)
Next n
End If
End With
End Sub

Now, how to trigger all of this...

I have a toolbar with just one button on it: a "Rerun" button. When a
document based on this template is opened, this toolbar is displayed. If the
user clicks on the button, the code for creating the document is launched.
Because this is the same code that's called in the AutoNew procedure, this
code checks to see if this a new document or an existing one, like so:

Private Sub UserForm_Initialize()
If fcnFindVar("NewDoc") Then
If LCase(myDoc.Variables("NewDoc").Value) = "true" Then LoadDefaults
Else LoadDocumentVars
Else: LoadDefaults
End If
End Sub

This has been stripped down substantially - stuff like building ComboBox
lists and enabling/disabling various other controls has been left out - but
you should get the idea. The relevant portions of 'LoadDocumentVars' is
below, followed by 'LoadDefaults'.

Private Sub LoadDocumentVars()
LoadCustomerVars
LoadGoodsVars
End Sub

Private Sub LoadDefaults()
optCustomerCompany.Value = True
cboGoodsType.ListIndex = 0
End Sub

A lot to take in, I know, but if you take your time and sort through it
carefully, I'm sure you can work it out. Feel free to post back if you have
any questions.
--
Cheers!
Gordon
The Kiwi Koder

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
S

SoCal Rick

Wow Gordon,
Have you written a book yet? This is a fantastic education. You were
correct that it will take a few readings to understand all of it. But this
will really strectch me. So thank you,
Rick
 
G

Gordon Bentley-Mix

My pleasure Rick. Glad I could help.

And no, I haven't written a book - but maybe I should. I could begin by
gleaning the good bits from my posts...

I thought maybe it would be helpful if I picked apart some of the stuff I
provided to you previously in a series of separate posts, starting with the
process for collecting the UserForm values. I see that I went over that at a
pretty high level, so it's probably a good place to start adding detail.

Let's begin with the AutoNew macro - majorly stripped down to make things as
simple as possible - so you can come to grips with the whole "myDoc",
"myForm" stuff.

It all starts with the declarations - Public for the things that have to
cross boundaries between the document and the UserForm and normal Dim
statements for everything else.

Option Explicit

Public myDoc As Document
Public myForm As frmUserForm1
Public bNewDoc As Boolean
Public CustomersArray() As Variant
Public CustomerCount As Integer

Dim GoodsTypeIdx As Integer
Dim NewUsedOption As String
Dim GoodsField1 As String
Dim GoodsField2 As String
Dim GoodsField3 As String
Dim GoodsDescription As String
Dim bAttachedScheduleChk As Boolean

Then just a simple bit of code to set the Document object to the
ActiveDocument and make the call to run the template.

Sub AutoNew()
Set myDoc = ActiveDocument
RunTemplate
End Sub

The RunTemplate code does a few things - most notably: initialise an
instance of the UserForm, call the procedures for collecting the UserForm
values and building the document, and display the "Rerun" toolbar. (Note that
the "Rerun" functionality does basically the same thing - the only difference
being that it checks to see if the ActiveDocument is a document first, since
"Rerun" can't be used on a template.)

Public Sub RunTemplate()
Set myForm = New frmUserForm1
Load myForm
myForm.Show
If bNewDoc = True Then CollectUserFormValues
Unload myForm
Set myForm = Nothing
If bNewDoc = True Then
BuildNewDoc
SetToolbar
Else
If fcnFindVar("NewDoc") Then
If LCase(myDoc.Variables("NewDoc").Value) = "true" Then
myDoc.Close wdDoNotSaveChanges
End If
End If
End Sub

The bNewDoc variable is critical here; it's a flag that gets set when either
the 'OK' or 'Cancel' button is clicked on the UserForm, as shown in the code
below.

Private Sub btnOK_Click()
bNewDoc = True
Me.Hide
End Sub

Private Sub btnCancel_Click()
Dim myResult As Integer
myResult = MsgBox("Are you sure you want to cancel this Document?",
vbYesNo, "Cancel Lease")
If myResult = 6 Then
bNewDoc = False
Me.Hide
End If
End Sub

The "NewDoc" doc var is also important; I manually added it to the template
with a value of "true" whilst doing the coding. Then when I actually build a
document from the template, I set it to "false". This way I can tell whether
the document I'm working with is one that's just been created or an existing
document that's been opened for editing. This has a bearing in a couple of
places in code, but in this instance I just use it to determine whether myDoc
should be discarded when the 'Cancel' button (which has a bit of a "safety
net" around it) is clicked.

CollectUserFormValues includes a call to CollectGoodsDetails, which I posted
previously and have re-posted here:

Private Sub CollectGoodsDetails()
With myForm
GoodsTypeIdx = .cboGoodsType.ListIndex
Select Case True
Case .optNewGoods.Value
NewUsedOption = "New Goods"
Case .optUsedGoods.Value
NewUsedOption = "Used Goods"
End Select
GoodsField1 = .txtGoodsFld1.Value
GoodsField2 = .txtGoodsFld2.Value
GoodsField3 = .txtGoodsFld3.Value
GoodsDescription = .txtGoodsDescr.Value
bAttachedScheduleChk = CBool(.chkAttachedSchedule.Value)
End With
End Sub

This is pretty straight forward, but now you get a feel for the relationship
between the variables declared at the beginning and the controls on the
UserForm. I'm sure you can follow my control naming convention: cbo=ComboBox,
txt=TextBox, opt=OptionButton, chk=CheckBox.

And just to finish off, the "Rerun" code:

Sub RerunTemplate()
Set myDoc = ActiveDocument
If myDoc.Type = wdTypeDocument Then
RunTemplate
ElseIf myDoc.Type = wdTypeTemplate Then
MsgBox "The Rerun functionality cannot be used with a Template.",
vbCritical, "Rerun"
End If
End Sub

I suppose the next logical step would be to show you how I put the stuff
into the "parties" array. I'll see if I can squeeze this in on my next break.
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
G

Gordon Bentley-Mix

Rick,

As promised, adding values to the "parties" array.

We'll start with the relevant declarations. These are part of the UserForm
code - just a flag to indicate when we're editing an existing Customer and a
pointer to the Customer record that's being edited.

Option Explicit
Dim bEditingCustomer As Boolean
Dim EditedCustomerIdx As Integer

Then the code behind the "Add Customer" button on the UserForm. This just
validates the values in the various TextBoxes and then either adds the
details of a new Customer updates the details of an existing Customer.

Private Sub btnAddCustomer_Click()
If fcnCustomerDetailsOK = True Then
btnAddCustomer.Caption = "Add"
If Not bEditingCustomer Then AddCustomer Else UpdateCustomer
On Error Resume Next
txtCustAddressL1.Value = ""
txtCustAddressL2.Value = ""
With txtCustomerName
.Value = ""
.SetFocus
End With
LoadCustomersList
End If
End Sub

Code to add a new Customer to the array:

Private Sub AddCustomer()
CustomerCount = CustomerCount + 1
ReDim Preserve CustomersArray(3, 1 To CustomerCount) As Variant
CustomersArray(0, CustomerCount) = txtCustomerName.Value
CustomersArray(1, CustomerCount) = txtCustAddressL1.Value
CustomersArray(2, CustomerCount) = txtCustAddressL2.Value
Select Case True
Case optCustomerIndividual.Value
CustomersArray(3, CustomerCount) = "I"
Case optCustomerCompany.Value
CustomersArray(3, CustomerCount) = "C"
Case optCustomerTrust.Value
CustomersArray(3, CustomerCount) = "T"
End Select
End Sub

And the code to update an existing Customer:

Private Sub UpdateCustomer()
CustomersArray(0, EditedCustomerIdx) = txtCustomerName.Value
CustomersArray(1, EditedCustomerIdx) = txtCustAddressL1.Value
CustomersArray(2, EditedCustomerIdx) = txtCustAddressL2.Value
Select Case True
Case optCustomerIndividual.Value
CustomersArray(3, EditedCustomerIdx) = "I"
Case optCustomerCompany.Value
CustomersArray(3, EditedCustomerIdx) = "C"
Case optCustomerTrust.Value
CustomersArray(3, EditedCustomerIdx) = "T"
End Select
bEditingCustomer = False
End Sub

And finally, the code to initiate the process for editing an existing
Customer, which is called when the "Edit Customer" button is clicked on the
UserForm:

Private Sub btnEditCustomer_Click()
If lstCustomers.ListIndex <> -1 Then
EditedCustomerIdx = lstCustomers.ListIndex + 1
btnAddCustomer.Caption = "Update"
btnDelCustomer.Enabled = False
Select Case CustomersArray(EditedCustomerIdx, 3)
Case "I"
optCustomerIndividual.Value = True
Case "C"
optCustomerCompany.Value = True
Case "T"
optCustomerTrust.Value = True
End Select
txtCustomerName.Value = CustomersArray(0, EditedCustomerIdx)
txtCustAddressL1.Value = CustomersArray(1, EditedCustomerIdx)
txtCustAddressL2.Value = CustomersArray(2, EditedCustomerIdx)
bEditingCustomer = True
On Error Resume Next
txtCustomerName.SetFocus
End If
End Sub

Some things to note about this:
* The ListBox for displaying the list of Customers is 0 based while the
first record in the CustomersArray is at 1, so the pointer to the Customer
record to edit must be set to the ListBox ListIndex plus 1 (EditedCustomerIdx
= lstCustomers.ListIndex + 1).
* The caption on the "Add Individual" button gets changed to "Update" when
a Customer is being edited and changed back to "Add" when the edits are
complete. Also the "Delete Customer" button (discussed below) is disabled
when editing.
* I've also left out the code for the "validation" function, but basically
all it does is make sure none of the required fields are blank.

I also have a button for deleting Customer records, which works similarly:

Private Sub btnDeleteCustomer_Click()
If lstCustomers.ListIndex <> -1 Then
Dim DelIndex As Integer
Dim myResult As Integer
DelIndex = lstCustomers.ListIndex + 1
myResult = MsgBox("Delete Customer" & CustomersArray(0, DelIndex),
vbOKCancel, "Delete Name")
If myResult <> 2 Then
DeletelstCustomersLine DelIndex
LoadCustomersList
On Error Resume Next
txtCustomerName.SetFocus
End If
End If
End Sub

The code that does the "heavy lifting":

Private Sub DeletelstCustomersLine(DeleteLine As Integer)
Dim i As Integer
Dim n As Integer
CustomerCount = CustomerCount - 1
If DeleteLine <= CustomerCount Then
For i = DeleteLine To CustomerCount
For n = 0 To 3
CustomersArray(n, i) = CustomersArray(n, i + 1)
Next n
Next i
End If
If CustomerCount > 0 Then
ReDim Preserve CustomersArray(3, 1 To CustomerCount) As Variant
Else: Erase CustomersArray
End If
End Sub

This just moves all the values in the array that are "below" the record to
be deleted "up" one position in the array and then chops off the "last"
record. The only tricky bit is around what to do when there is just one
Customer in the list/array.

One last thing to note here. See the CustomerCount variable that gets
incremented/decremented when adding/deleting Customers? This is a Public
variable that gets used in the code for saving the Customer details in the
doc vars as well. You can see where I declared it in my previous post.

I think that about does it on the data collection side. I see that I left
out the code for populating the ListBox (LoadCustomersList), but I put it in
my initial post so you can just refer to that.

I'm not sure where to go next. Anything you'd like more explanation on?
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
G

Gordon Bentley-Mix

Oops! Made a little mistake in my last post.

For consistency, in the Private Sub btnEditCustomer_Click()
procedure the line
btnDelCustomer.Enabled = False
should be
btnDeleteCustomer.Enabled = False

I'm "sanitising" my code as I go and missed this one.
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
G

Gordon Bentley-Mix

Rick,

Just one last post to tidy up a few loose ends.

In my initial post, you might have noticed that when working with the values
of the document variables, I always use " " (a single space) rather than ""
(an empty string). This is because doc vars cannot be empty, and if you
create a doc var without specifying a value, the value defaults to " ".

I may not have made it clear exactly where each bit of sample code goes in
the project. As I said in my first post, I like to keep the "document ops"
code separate from the UserForm-related code. This means that the only code
in the UserForm module is that code _directly_ involved with the
functionality provided by the UserForm - things like initialisation and
validation code, manipulation of labels and captions, enabling/disabling
controls, etc. Everything else goes in the "main" module, including the
Public declarations.

I haven't provided any direction on how I get the values from my UserForm
into my document. I do use a lot of formfields, and I show/hide bookmarked
content as well; only rarely do I actually write content directly into the
document. However, I do all of this using the "collected" values from the
UserForm and not the properties of the UserForm controls themselves. You'll
notice that I destroy the UserForm object before I start building the
document. I do this because it frees up memory and also because, in some
cases, I display another UserForm or a built-in dialog and want to avoid
conflicts between modal forms. (See my previous posts on "Hanging Code" for
more info.)

When I do put content into a formfield I use a Public procedure with
arguments to do so, as follows:

Public Sub InsertFormFieldValue(BkmkName As String, Result As String)
With myDoc
If .Bookmarks.Exists(BkmkName) Then .FormFields(BkmkName).Result =
Result
End With
End Sub

This includes a bit of validation to ensure that the bookmark exists before
trying to write into the field, and gets called like this:

Private Sub LoadGoodDetails()
InsertFormFieldValue "txtNewUsed", NewUsedOption
InsertFormFieldValue "txtType", GoodsTypeVal
InsertFormFieldValue "txtMake", GoodsField1
InsertFormFieldValue "txtModel", GoodsField2
InsertFormFieldValue "txtGD1", UCase(GoodsField3)
End Sub

When I write content into a bookmark (as opposed to a formfield) I take
steps to "retain" the bookmark so it's available if the template is rerun. As
I mentioned previously, for AutoText entries this means that the bookmark is
part of the entry. However, for writing content through code, I do something
like this:

Public Sub InsertBookmarkValue(BkmkName As String, InsertValue As String)
With myDoc
If .Bookmarks.Exists(BkmkName) Then
Dim myRange As Range
Set myRange = .Bookmarks(BkmkName).Range
myRange.Text = InsertValue
.Bookmarks.Add BkmkName, myRange
End If
End With
End Sub

Finally, a real "belt-n-braces" bit of code for making the "Rerun" toolbar
available:

Public Sub SetToolbar()
Dim bBarFound As Boolean
Dim myCommandBar As CommandBar
bBarFound = False
For Each myCommandBar In CommandBars
If myCommandBar.Name = "Rerun" Then
bBarFound = True
Exit For
End If
Next myCommandBar
If Not bBarFound Then
CommandBars.Add "Rerun"
With CommandBars("Rerun")
.Position = msoBarTop
.Controls.Add Type:=msoControlButton, ID:=1
With .Controls(1)
.FaceId = 1020
.Caption = "Rerun Template"
.Style = msoButtonIconAndCaption
.OnAction = "RerunTemplate"
End With
.Visible = True
End With
Else
With CommandBars("Rerun")
.Position = msoBarTop
With .Controls(1)
If .Type = msoControlButton Then
.Caption = "Rerun Template"
.FaceId = 1020
.Style = msoButtonIconAndCaption
.OnAction = "RerunTemplate"
End If
End With
.Visible = True
End With
myDoc.AttachedTemplate.Saved = True
End If
End Sub

I'll leave it to you to work out what's going on here. However, if you
decide to step the code to see what's going on, please be aware that there
are more than 140 CommandBar objects in the CommandBars collection in Word
2003... :-D
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
E

EBMurf

Gordon,

Wonderful tutorial on how to work with doc variables, userforms, and
templates. Thanks very much. I learned a lot from reading your post.
 
G

Gordon Bentley-Mix

Glad I could help. Let me know if you have any questions.
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top