Word VBA Field IF Docproperty Toggle View カスタムプロパティで文字の表示非表示を一気に切り替える及びそのマクロ

# フィールド.コードで文字の表示非表示を切り替える
## フィールドコードとフィールドの違い
どうでも良いが
[Word のフィールド コード一覧](https://support.microsoft.com/ja-jp/office/word-%E3%81%AE%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89-%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%80%E8%A6%A7-1ad6d91a-55a7-4a8d-b535-cf7888659a51)
としながら
[Word でフィールドを挿入、編集、表示する](https://support.microsoft.com/ja-jp/office/word-%E3%81%A7%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5-%E7%B7%A8%E9%9B%86-%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B-c429bbb0-8669-48a7-bd24-bab6ba6b06bb)
といつの間にかフィールドになってしまう。

これは中括弧自体はフィールドであり、フィールドは種類を指している。そして、フィールドの文字がフィールドコードらしい。VBAでは[Field.Code](https://docs.microsoft.com/ja-jp/office/vba/api/word.field.code)となっている。

## Word.FieldとWord.Rangeの違い
またこの解説で
>フィールドのコード を 表す Range オブジェクトを返します。 値の取得と設定が可能です。

となっているのでWord.Rangeよりは上の概念なのだとわかる。
フィールドの目的はAccessやExcelでも意味合いが違う。
WordにおいてはRangeとはある一定の範囲という意味しかない。長さ0で現在位置でもActiveCellではなく、Selection.Rangeとなる。
この一定の範囲にスィッチを加えて、あるいは外部データ、プロパティ、ドキュメントの他のRangeを引用し、加工して表示できるのがFieldである。
オブジェクト、プロパティまたはRangeまたは外部データ+書式、固有スィッチ＝Field
である。
フィールドを最初に意識するのは一般的に差し込み印刷(Mergefield)であろう。

## 手順
<ol>
 <li> フィールドコードのDocPropertyのためカスタムプロパティを設定する<br>ALT+F 情報</br><br>プロパティ</br><br>詳細プロパティ</br><br>プロパティ名Draft</br><br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/faffecc8-3b48-7c1d-573a-fb18c78b9223.png)

</br>
<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/7eadccd3-038f-a25c-a9ff-178bff5a3024.png)

</br>
<br>値を変更するときはDraftをクリックして値を変更し、変更をクリック</br>
<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/6e6cb5b6-b33d-1118-d42e-9adccdf8065d.png)

</br></li> 
<li>画面を戻してCTRL+F9でフィールドコードを表示 IF 半角空白を入れる<br>`{ IF {DocProperty Draft} = "Y" "案1" ""}`</br></li> 
<li>更新する</li>
<li>プロパティを変更して表示を切り替えるときは1.の値の変更を行って、「更新F9」をする</li>
<li>ファイルを他人に渡す場合等はフィールドコードの更新、フィールドのリンクを解除するを実行し、プロパティを削除して別名で保存する。もしくはPDFで発行して、ドキュメント情報を削除する。</li>
</OL>

## ポイント
 1. フィールドコードの式にイコールとカッコはいらない
 2. DocPropertyのYesNoの値はTrue Falseではなく Y N
 3. きちんと半角空白を入れる
 4. 非表示は`""`(NullString)
 5. 囲み文字などの装飾が有効
 6. 中カッコ`{}`はCtrl+F9で入れる。この段階で一度保存する。
 7. 最後にフィールドを更新して、フィールドのリンクを解除してからプロパティを消して別名で保存する
 8. Optionの設定に注意
 9. 文字列を指定する場合には値は255文字まで。それ以上になった場合にはクィックパーツの定型句を使う。

#### DocProperty以外の方法

:a: フィールドの書き換えで文字列をコントロールする方法としては、隠し文字を使い、オプションで切り替える方法:camera:も考えられるが、印刷されないだけで、文字自体は自動で削除されない。
:b: 可能かどうかは不明だが、定型句を切り替える方法も考えられる。しかし、定型句自体がテンプレートやbuildingblock.dotxに保存される。Doc*ファイル単体で文字列を切り替える、という方法はこのユーザー設定プロパティとフィールドを組み合わせるしかないようだ。
:C: DocVariableもあるが、これはVBAが必要となる。
:green_book: この方法が簡単とはいいがたいが、かといってほかの方法が使いやすいとも言えない。マクロを要しない分だけDocpropertyフィールドを使う方が容易だともいえる。


### 1.フィールドコードの式にイコールとカッコはいらない
フィールドの編集で式からIF関数を選ぶとイコールとカッコがつくが、いらない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/082986d5-3ef5-c917-18a5-b46b732ddd29.png)
加減乗除の場合は必要だが、この場合は不要。なんで余計なものをつけるんだ。。。

### 2.DocPropertyのYesNoの値はTrue Falseではなく Y N
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/a36b4791-843c-9037-a1de-1d62aca90ebd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/4b40a708-fb59-8c1a-8b88-9e71f44a963b.png)
このようにDocPropetyを表示すると半角大文字でY/Nが表示される
このため`="Y"`や`="N"`というふうに結ばれる。つまり値は文字列だということらしい。
しかし、後述するがマクロではBoolean、つまり通常はTrue Falseが返ってくる。極めて珍しい。
IFフィールドとDocPropertyは
[IF statement and DocProperty field as conditional text controls? ](https://answers.microsoft.com/en-us/msoffice/forum/all/if-statement-and-docproperty-field-as-conditional/d2516207-ee65-e011-8dfc-68b599b31bf5)
> { IF { DOCPROPERTY myproperty } = "whatever" "same" "different" }

このように等価であるかどうかというサンプルしかない。True/Falseではなく、Y or NというのではIFフィールドを使いこなせないのも道理である。

### 3.きちんと半角空白を入れる
空白が入っているところは必ず空白を入れる。そうしないとエラーが生じる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/49bea726-1f4d-9e4b-9f43-ebabf10cf491.png)

###  4. 非表示は`""`(NullString)
3.の画像で表示しているとおり`""`Noの場合は文字列がない。VBの定数としてはvbNullStringである。これで非表示を作り出している。
こうすると文字データ自体がなくなるので、リンクを解除した段階で文字が削除されたことになる。

### 5. 囲み文字などの装飾が有効
囲み文字やフォントの大きさなどが指定すると反映されるため、単なる文字列としては扱われていないらしい。
3．の例は囲み文字になっているが、実際にYの場合にはこの設定が反映される。

### 6.中カッコ`{}`はCtrl+F9で入れる。この段階で一度保存する。
今回の場合2回入れる。IFの前に一度、IFをいれて半角スペースを入れてCtrl+F9をいれてDocProperty Draftと入力。
プロパティ名を英語にしている方が入力が早いしバグの恐れがない。なお、プロパティ名は組み込みプロパティ、関数、定数として扱われるようなものは避けること。たとえばwdCpをつけてプロパティ名をつけるなど。例`wdCp_Name` :red_circle: wdCp Word CustomDocumentProperty
また、フィールドを入れ終わったら、一旦ファイルを保存する。
今回の記事では影響がないが、組み込みプロパティとリンクしている場合は保存する必要があるとされている。また、せっかく設定したフィールドが飛ぶと通常の入力より手間なので、ダメージが大きい。

[DocumentProperties.Add メソッド (Office)](https://docs.microsoft.com/ja-jp/office/vba/api/office.documentproperties.add)
>Office ドキュメントの特定の値にリンクしているドキュメント プロパティを DocumentProperties コレクションに追加する場合、DocumentProperty オブジェクトに正しくドキュメント プロパティが追加されているかどうかを確認するには、Office ドキュメントをあらかじめ保存しておく必要があります

最も[Documnt.Container](https://docs.microsoft.com/ja-jp/office/vba/api/word.document.container)は通常は使わない。
`LinkToContent: = False` は必須だが、値を設定してフィールドに使うという目的であれば、Falseで固定とみなしていいと思われる。
LinkSourceはBulitin以外は使わないと思われるし、使うならならばBuiltInそのものを使うだろう。

###  7. フィールドを更新して、フィールドのリンクを解除してからプロパティを消して別名で保存する
フィールドを操作されても仕方がないので、
ALT+F9でフィールドコードをすべて表示
[フィールドをすべて更新する−全選択後F9キー -relief](https://www.relief.jp/docs/002553.html)
あるいは公式のHPにあるように印刷前にフィールドを更新でも良い。
[フィールドを更新する](https://support.microsoft.com/ja-jp/office/%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B-7339a049-cb0d-4d5a-8679-97c20c643d4e)
CTRL+A -> F9
あるいはフィールドの計算結果だけを表示させるてフィールドを消すことを<b>フィールドのリンクを解除</b>するという。しかし、実際はリンクしていないものばかりである。BuiltInもFalseなので、リンクを解除するものはほぼないというのが実情である。
`フィールドのリンクを解除する。 Ctrl + Shift + F9` 公式HPでもやはりリンクを解除という訳のわからないタイトルになっている。
CTRL+A -> CTRL+SHIFT+F9
フィールドコードが残っていないかを確認するにはF11キー、Shift+F11キーでフィールドに移動しないかを確認する。完全に消えている場合にはカーソルが移動しない。
[word-のキーボード-ショートカット](https://support.microsoft.com/ja-jp/office/word-%E3%81%AE%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89-%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88-95ef89dd-7142-4b50-afb2-f762f663ceb2#bkmk_mergefieldswin)
公式ホームページではここではフィールドとなっている。普通の人がわけがわからなくなるのは当たり前であろう。
なお、フィールドのロックは、ロックを外すのが簡単なのでこういう場合は使うべきではないだろう。
[覚えれば上級者！Wordのフィールドに関するショートカットキー](https://office-hack.com/word/shortcutkey-field/)

# VBA
## オプションの定義
OptionをVBAでコントロールすると、Option とか色々混在する。
Wordが出来合いで間に合わせながら作ったいい加減さが伺える。

Viewは

```vb
ActiveDocument.ActiveWindow.View.FieldShading = _ 
 wdFieldShadingAlways
```

とViewオブジェクトが、Document Windowの下にあるというのがポイント

[View.ShowBookmarks](https://docs.microsoft.com/ja-jp/office/vba/api/word.view.showbookmarks)
> True の 場合は先頭と末尾の各ブックマークの角かっこが表示

[View.ShowFieldCodes](https://docs.microsoft.com/ja-jp/office/vba/api/word.view.showfieldcodes)
> True の場合は、フィールド コードが表示されます。

更新しても実行結果が表示されない

[Options.PrintFieldCodes](https://docs.microsoft.com/ja-jp/office/vba/api/word.options.printfieldcodes)
> True の場合Microsoft Word結果の代わりにフィールド コードを印刷します。

下書きの段階で使うときもあるが、通常はFalseで固定したほうが良い。

[Options.UpdateFieldsAtPrint](https://docs.microsoft.com/ja-jp/office/vba/api/word.options.updatefieldsatprint)
> True ドキュメントを印刷する前に自動的にフィールドが更新される
<b>このオプションはTrue推奨</b>
:::note info
ただし、印刷（PDFへのExportを含む？)を実行すると値が同じでも更新されたことになり、保存を要求されます。
このため、ドラフト段階を終えて、完成した後はこのオプションはFalseにしてもいいと思います。
:::

[View.FieldShading](https://docs.microsoft.com/ja-jp/office/vba/api/word.view.fieldshading)
[WdFieldShading](https://docs.microsoft.com/ja-jp/office/vba/api/word.wdfieldshading)定数。
<b>通常は2。</b>
ただし最終チェック時に1に切り替えて網掛けにして確認する、という使い方ができる。


```vb
Sub WordFieldCodeOption()
    ActiveWindow.View.ShowBookmarks = True
    ActiveWindow.View.ShowFieldCodes = Not ActiveWindow.View.ShowFieldCodes
    Options.UpdateFieldsAtPrint = True
    Options.UpdateLinksAtPrint = True
    Options.PrintFieldCodes = True
End Sub
```

## フィールドの操作
フィールドを実行結果とフィールドコードに切り替えるのをオプションで実行
混在している場合に統一したい場合は使える。

```vb
Sub toggleShowWordFieldCodes()
    ActiveWindow.View.ShowFieldCodes = Not ActiveWindow.View.ShowFieldCodes
End Sub
```

すべてのフィールドコードを実行結果をコードに切り替えるまたはその逆。
ただしToggleなので、フィールドコードはすべて実行結果（F9更新）していることが前提。
混在する場合はオプションで切り替える。

```vb
Sub ShowAllFieldcodes()
    Selection.WholeStory
    ActiveWindow.View.ShowFieldCodes = Not ActiveWindow.View.ShowFieldCodes
End Sub
```

フィールドが実行結果を表示している状態で、個々のフィールドを更新する


```vb
Sub runUpdateFields()
' built in Macroで実行する
Dim wFld As Word.Field
For Each wFld In ThisDocument.Fields
wFld.Select
Application.Run MacroName:="UpdateFields"　' 組み込みマクロを利用
' wfld.Update 'でもよい
Next
End Sub
```

Ctrl+AとF9で更新した場合のマクロ
フィールドコードはすべて実行結果（F9更新）していることが前提。

```vb
Sub WordDocumentAllFieldUpdate()
' フィールドコードが実行結果を表示している状態で実行
    Selection.WholeStory
    Selection.Fields.Update
End Sub
```

## フィールドコードの挿入
今回の案1が囲み文字で表示されるマクロ
カーソル位置に挿入される。
キーボード操作の記録で作成したためか、囲み文字を設定すると一度空白をいれて切らないといけない。また囲み文字属性があるときは逆転するので注意。書式を一度クリアして、標準スタイルのような状態で実行すること。



```vb
Sub InsertFieldCode()
    Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, _
        PreserveFormatting:=False
    Selection.TypeText Text:="IF "
    Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, _
        PreserveFormatting:=False
    Selection.TypeText Text:="Docproperty Draft"
    Selection.MoveRight Unit:=wdCharacter, Count:=2
    Selection.TypeText Text:=" =""Y"" ""案1"""
    Selection.MoveLeft Unit:=wdCharacter, Count:=1
    Selection.MoveLeft Unit:=wdCharacter, Count:=2, Extend:=wdExtend
    With Selection.Font.Borders(1)
        If .LineStyle = wdLineStyleNone Then
            .LineStyle = Options.DefaultBorderLineStyle
            .LineWidth = Options.DefaultBorderLineWidth
            .Color = Options.DefaultBorderColor
        Else
            .LineStyle = wdLineStyleNone
        End If
    End With
    Selection.Font.Shrink ’グリッドを超える時があるので縮小している
    Selection.MoveRight Unit:=wdCharacter, Count:=2
    Selection.TypeText Text:=" """""
    Selection.Fields.Update
End Sub
```

## ユーザーが設定するプロパティをVBAで設定、変更、削除する
[Document.CustomDocumentProperties プロパティ (Word)](https://docs.microsoft.com/ja-jp/office/vba/api/word.document.customdocumentproperties)
>Properties of type msoPropertyTypeString (MsoDocProperties) cannot exceed 255 characters in length.
>msoPropertyTypeString 型のプロパティ (MsoDocProperties) の長さは 255 文字を超えることはできません。

とあるが、文字列の値の長さが255文字という意味だと思われる。
これを超える場合にはクィックパーツの定型句（AutoText)を使う。

[DocumentProperty.Value プロパティ](https://docs.microsoft.com/ja-jp/office/vba/api/office.documentproperty.value)
[DocumentProperty.LinkSource プロパティ (Office)](https://docs.microsoft.com/ja-jp/office/vba/api/office.documentproperty.linksource)
このユーザーが設定する詳細プロパティをCustomPropertiesのコレクションとしている。
Draftと名前がかぶると大変なので、Testファイルかどうかを意味するTestFileというプロパティを設定する。
Yes/No型で、最初のValueはTrueとする

```vb
Sub AddUserCustomProperty_TestFile_Boolean_True()
ThisDocument.CustomDocumentProperties.Add _
Name:="TestFile", LinkToContent:=False, Value:=True, _
Type:=msoPropertyTypeBoolean
End Sub
```

次に変更する。勘のいい人ならこれは名前で指定だろうと予測できるだろう。Index番号もあるが、追加したり削除したりすれば変わるので、名前指定のほうが実際は使えると思われる。
またこの前段の上位オブジェクトであるDocumentも要注意である。
ActiveDocument Thisdocument 開いているファイルの名前を指定する
といいうことが考えられる。
とりあえずモジュールを設定しているDocumentとしてサンプルを記述する。
[Document.CustomDocumentProperties プロパティ (Word)](https://docs.microsoft.com/ja-jp/office/vba/api/word.document.customdocumentproperties)
[MsoDocProperties](https://docs.microsoft.com/ja-jp/office/vba/api/office.msodocproperties)
msoPropertyTypeNumber 	1 	整数型 (Integer) の値
マクロで設定すると整数型を設定することができる。
面白いのは、返すのは[DocumentProperties オブジェクト](https://docs.microsoft.com/ja-jp/office/vba/api/office.documentproperties)としているが、このオブジェクトは<b>Wordではaddメソッド以外全く使えない</b>オブジェクトです。
Countすらできない。BuiltInかCustomを使用する。またWordではなくOfficeのオブジェクトになる。
[Office VBA リファレンス DocumentProperties オブジェクト DocumentProperties のメンバー DocumentProperties.Add メソッド (Office)](https://docs.microsoft.com/ja-jp/office/vba/api/office.documentproperties.add)


### 整数型を設定すると小数点がカットされることが確認できるサンプルコード

```vb
Sub AddUserCustomProperty_IntTest_Boolean_True()
ThisDocument.CustomDocumentProperties.Add _
Name:="IntTest", LinkToContent:=False, Value:=41.1, _
Type:=msoPropertyTypeNumber
End Sub
```

例えばこのようにすると数値は41になる。
ご存知の方もいるかも知れないが、Wordも演算誤差が生じるので、整数型で設定できるものは整数型で設定したほうが良い。
また、小数点が含まれるものは、必ず表示形式（スィッチ）を設定し、小数点切り捨て、四捨五入が行われるようにすること。


```vb
Sub UpdateUserCustomProperty_TestFile_Boolean_False()
ThisDocument.CustomDocumentProperties("TestFile").Value = False
End Sub
```


#### 削除

```vb
ThisDocument.CustomDocumentProperties("IntTest").Delete
```

# まとめ
案を切り替える、ドラフトを切り替えるというのはユーザープロパティの値を変更して、更新をかけるだけでできるようになる。
1つ2つなら手作業でも良いが、5を超える場合はこれでかなりの時短になる。
相手方にファイルを渡さずPDF等で渡せば、別にファイルを保存する必要もない。
完全に動くかどうかは不明だが、一応単純なフィールドコードであれば、このようにシンプルにまとまる。
Subがついていないものは適宜追加すること。

### オプションの定義

```vb
    ActiveWindow.View.ShowBookmarks = True
    ActiveWindow.View.FieldShading = wdFieldShadingWhenSelected
    ActiveWindow.View.ShowFieldCodes = False
    Options.UpdateFieldsAtPrint = True
    Options.UpdateLinksAtPrint = True

```

### プロパティ定義

```vb
On Error Resume Next
ThisDocument.CustomDocumentProperties("Draft").Delete
ThisDocument.CustomDocumentProperties.Add _
Name:="Draft", LinkToContent:=False, Value:=True, _
Type:=msoPropertyTypeBoolean

```

### 挿入
カーソルがある位置に挿入DraftがTrueなら"Drafts"と表示

```vb
With Selection
    .Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, _
        PreserveFormatting:=False
    .TypeText Text:="IF "
    .Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, _
        PreserveFormatting:=False
    .TypeText Text:="DocProperty Draft"
    .MoveRight Unit:=wdCharacter, Count:=2
    .TypeText Text:=" = ""Y"" ""Drafts"" """""
    .Fields.Update
End With
```

保存

### 更新

```vb
Sub FieldUpdate()
ThisDocument.CustomDocumentProperties("Draft").Value = False
ThisDocument.Fields.Update
End Sub
```

### 最終処理

```vb
Sub TerminalFieldsUpdateAndUnlink()
ThisDocument.Fields.Update
ThisDocument.Fields.Unlink
ThisDocument.CustomDocumentProperties("Draft").Delete
End Sub
```