# M16.8.15.5.3.4 v2.6
    # Filter状態が残っている間だけ前回条件・値を復元する。
    # 「この列のFilter解除」等では DisplayFilterStates から削除されるため、
    # 解除後に再表示した場合は自動的に初期状態になる。
    $savedFilterState =
        Get-HashEditorDisplayFilterState `
            -ColumnName $ColumnName

    if ($null -ne $savedFilterState) {

        $savedConditionDisplayText =
            Get-HashEditorFilterConditionDisplayText `
                -Condition ([string]$savedFilterState.Condition) `
                -InputType $filterInputType

        $savedConditionIndex =
            $comboCondition.Items.IndexOf(
                [string]$savedConditionDisplayText
            )

        if ($savedConditionIndex -ge 0) {

            $comboCondition.SelectedIndex =
                $savedConditionIndex
        }

        if ($isChoiceFilter) {

            $savedChoiceIndex =
                $choiceValue.Items.IndexOf(
                    [string]$savedFilterState.Value
                )

            if ($savedChoiceIndex -ge 0) {

                $choiceValue.SelectedIndex =
                    $savedChoiceIndex
            }
        }
        elseif ($isBooleanFilter) {

            $savedBooleanIndex =
                $booleanValue.Items.IndexOf(
                    [string]$savedFilterState.Value
                )

            if ($savedBooleanIndex -ge 0) {

                $booleanValue.SelectedIndex =
                    $savedBooleanIndex
            }
        }
        elseif ($isDateFilter) {

            $dateValue.Text =
                [string]$savedFilterState.Value
        }
        else {

            $savedMultiValues =
                @(
                    ConvertFrom-HashEditorMultiFilterValue `
                        -Value ([string]$savedFilterState.Value)
                )

            if ($savedMultiValues.Count -gt 0) {

                $textValue.Text =
                    [string]$savedMultiValues[0]
            }
        }
    }

    $updateValueInputState = {

        $condition =
            ConvertFrom-HashEditorFilterConditionDisplayText `
                -DisplayText ([string]$comboCondition.SelectedItem)

        $needsValue =
            Test-HashEditorTextFilterNeedsValue `
                -Condition $condition

        if ($isChoiceFilter) {

            $choiceValue.Enabled =
                $needsValue

            if (
                $needsValue -and
                $choiceValue.Items.Count -gt 0 -and
                $choiceValue.SelectedIndex -lt 0
            ) {

                $choiceValue.SelectedIndex =
                    0
            }

            if (-not $needsValue) {

                $choiceValue.SelectedIndex =
                    -1
            }
        }
        elseif ($isBooleanFilter) {

            $booleanValue.Enabled =
                $needsValue

            if (
                $needsValue -and
                $booleanValue.Items.Count -gt 0 -and
                $booleanValue.SelectedIndex -lt 0
            ) {

                $booleanValue.SelectedIndex =
                    0
            }

            if (-not $needsValue) {

                $booleanValue.SelectedIndex =
                    -1
            }
        }
        elseif ($isDateFilter) {

            $dateNeedsValue =
                Test-HashEditorDateFilterNeedsValue `
                    -Condition $condition

            $dateValue.Enabled =
                $dateNeedsValue

            $dateCalendarButton.Enabled =
                $dateNeedsValue

            $dateNoteMark.Enabled =
                $dateNeedsValue

            $dateInputHint.Enabled =
                $dateNeedsValue

            if (-not $dateNeedsValue) {

                $dateValue.Text =
                    ""
            }
        }
        else {

            $textValue.Enabled =
                $needsValue

            $buttonAddMultiValue.Visible =
                $needsValue

            $buttonAddMultiValue.Enabled =
                $needsValue

            if ($needsValue) {

                $labelValue.Text =
                    "値1"

                $textValue.Size =
                    New-Object System.Drawing.Size(
                        364,
                        32
                    )

                foreach (
                    $rowState in @(
                        $multiValueRows
                    )
                ) {

                    $rowState.Label.Visible =
                        $true

                    $rowState.TextBox.Visible =
                        $true

                    $rowState.TextBox.Enabled =
                        $true

                    $rowState.RemoveButton.Visible =
                        $true
                }
            }
            else {

                $labelValue.Text =
                    "値"

                $textValue.Size =
                    New-Object System.Drawing.Size(
                        400,
                        32
                    )

                $textValue.Text =
                    ""

                foreach (
                    $rowState in @(
                        $multiValueRows
                    )
                ) {

                    if ($null -ne $rowState.Label) {
                        $popup.Controls.Remove(
                            $rowState.Label
                        )
                        $rowState.Label.Dispose()
                    }

                    if ($null -ne $rowState.TextBox) {
                        $popup.Controls.Remove(
                            $rowState.TextBox
                        )
                        $rowState.TextBox.Dispose()
                    }

                    if ($null -ne $rowState.RemoveButton) {
                        $popup.Controls.Remove(
                            $rowState.RemoveButton
                        )
                        $rowState.RemoveButton.Dispose()
                    }
                }

                $multiValueRows.Clear()
            }
        }
    }

    $dateDeleteMode =
        @{
            Value = $false
        }

    $dateFormatGuard =
        @{
            Value = $false
        }

    $dateValue.Add_KeyDown({

        param(
            $sender,
            $e
        )

        if (
            $e.KeyCode -eq [System.Windows.Forms.Keys]::Back -or
            $e.KeyCode -eq [System.Windows.Forms.Keys]::Delete
        ) {

            $dateDeleteMode.Value =
                $true
        }
    })

    $dateValue.Add_TextChanged({

        param(
            $sender,
            $e
        )

        if ($dateFormatGuard.Value) {
            return
        }

        if ($dateDeleteMode.Value) {

            $dateDeleteMode.Value =
                $false

            return
        }

        $originalText =
            [string]$sender.Text

        $formattedText =
            Format-HashEditorFilterDateTypingText `
                -Text $originalText

        if ($formattedText -eq $originalText) {
            return
        }

        $dateFormatGuard.Value =
            $true

        try {

            $sender.Text =
                $formattedText

            $sender.SelectionStart =
                $sender.Text.Length
        }
        finally {

            $dateFormatGuard.Value =
                $false
        }
    })

    $dateValue.Add_Leave({

        param(
            $sender,
            $e
        )

        $parsedDate =
            ConvertTo-HashEditorFilterDate `
                -Value $sender.Text

        if ($null -ne $parsedDate) {

            $dateFormatGuard.Value =
                $true

            try {

                $sender.Text =
                    ([datetime]$parsedDate).ToString(
                        "yyyy/MM/dd"
                    )
            }
            finally {

                $dateFormatGuard.Value =
                    $false
            }
        }
    })

    $dateCalendarButton.Add_Click({

        param(
            $sender,
            $e
        )

        if (-not $isDateFilter) {
            return
        }

        $calendarForm =
            New-Object System.Windows.Forms.Form

        # M16.8.13.5 v7
        # 詳細入力画面のCalendarポップアップと同じ方式に統一。
        # タイトルバー・×・サイズ変更枠・余分な右側領域を表示しない。
        $calendarForm.FormBorderStyle =
            [System.Windows.Forms.FormBorderStyle]::None

        $calendarForm.StartPosition =
            [System.Windows.Forms.FormStartPosition]::Manual

        $calendarForm.ShowInTaskbar =
            $false

        $calendarForm.MinimizeBox =
            $false

        $calendarForm.MaximizeBox =
            $false

        $calendarForm.ControlBox =
            $false

        $calendarForm.SizeGripStyle =
            [System.Windows.Forms.SizeGripStyle]::Hide

        $calendarForm.AutoScaleMode =
            [System.Windows.Forms.AutoScaleMode]::None

        $monthCalendar =
            New-Object System.Windows.Forms.MonthCalendar

        $monthCalendar.MaxSelectionCount =
            1

        $parsedCurrent =
            ConvertTo-HashEditorFilterDate `
                -Value $dateValue.Text

        if ($null -ne $parsedCurrent) {

            $monthCalendar.SetDate(
                [datetime]$parsedCurrent
            )
        }

        # M16.8.13.5 v8
        # MonthCalendar.Size は環境/DPIによって余白を含む場合がある。
        # 1か月表示の実寸である SingleMonthSize を明示的に使い、
        # 右側・下側の余白を作らない。
        $singleMonthSize =
            $monthCalendar.SingleMonthSize

        $monthCalendar.Size =
            $singleMonthSize

        $monthCalendar.Margin =
            New-Object System.Windows.Forms.Padding(
                0
            )

        $monthCalendar.Location =
            New-Object System.Drawing.Point(
                0,
                0
            )

        $calendarForm.Padding =
            New-Object System.Windows.Forms.Padding(
                0
            )

        $calendarForm.ClientSize =
            $singleMonthSize

        [void]$calendarForm.Controls.Add(
            $monthCalendar
        )

        $calendarState =
            @{
                DateTextBox = $dateValue
            }

        $calendarForm.Tag =
            $calendarState

        $monthCalendar.Tag =
            $calendarState

        # Calendarボタンの直下へ表示。
        $buttonBottomPoint =
            New-Object System.Drawing.Point(
                0,
                $sender.Height
            )

        $buttonScreenPoint =
            $sender.PointToScreen(
                $buttonBottomPoint
            )

        # Calendarの右端とボタンの右端を揃える。
        # これによりポップアップはボタンから左側へ展開し、
        # 「右下にぶら下がる」見え方を避ける。
        $calendarLocation =
            New-Object System.Drawing.Point(
                (
                    $buttonScreenPoint.X +
                    $sender.Width -
                    $calendarForm.Width
                ),
                $buttonScreenPoint.Y
            )

        $calendarScreen =
            [System.Windows.Forms.Screen]::FromPoint(
                $calendarLocation
            )

        $workingArea =
            $calendarScreen.WorkingArea

        if (
            (
                $calendarLocation.X +
                $calendarForm.Width
            ) -gt
            $workingArea.Right
        ) {

            $calendarLocation.X =
                $workingArea.Right -
                $calendarForm.Width
        }

        if (
            (
                $calendarLocation.Y +
                $calendarForm.Height
            ) -gt
            $workingArea.Bottom
        ) {

            $buttonTopPoint =
                New-Object System.Drawing.Point(
                    0,
                    0
                )

            $buttonTopScreenPoint =
                $sender.PointToScreen(
                    $buttonTopPoint
                )

            $calendarLocation.Y =
                $buttonTopScreenPoint.Y -
                $calendarForm.Height
        }

        if ($calendarLocation.X -lt $workingArea.Left) {
            $calendarLocation.X = $workingArea.Left
        }

        if ($calendarLocation.Y -lt $workingArea.Top) {
            $calendarLocation.Y = $workingArea.Top
        }

        $calendarForm.Location =
            $calendarLocation

        $monthCalendar.Add_DateSelected({

            param(
                $calendarSender,
                $calendarEvent
            )

            $state =
                $calendarSender.Tag

            if (
                $null -ne $state -and
                $null -ne $state.DateTextBox
            ) {

                $state.DateTextBox.Text =
                    $calendarEvent.Start.ToString(
                        "yyyy/MM/dd"
                    )
            }

            $popupForm =
                $calendarSender.FindForm()

            if (
                $null -ne $popupForm -and
                -not $popupForm.IsDisposed
            ) {

                $popupForm.Close()
            }
        })

        # Calendar外クリックで閉じる。
        $calendarForm.Add_Deactivate({

            param(
                $formSender,
                $eventArgs
            )

            if (
                $null -ne $formSender -and
                -not $formSender.IsDisposed
            ) {

                $formSender.Close()
            }
        })

        $calendarForm.Add_FormClosed({

            param(
                $formSender,
                $eventArgs
            )

            $state =
                $formSender.Tag

            if (
                $null -ne $state -and
                $null -ne $state.DateTextBox
            ) {

                [void]$state.DateTextBox.Focus()
            }

            # M16.8.13.6.5 v2
            # Calendar終了後はFilter Popupへ明示的にフォーカスを戻す。
            # PowerShellコンソールが前面へ出るのを防ぐ。
            if (
                $null -ne $popup -and
                -not $popup.IsDisposed
            ) {

                $popup.Activate()
                [void]$popup.Focus()
                $popup.BringToFront()
            }
        })

        # Filter Popupを所有者として非モーダル表示。
        # 所有関係を明示してCalendar終了後の前面復帰先を安定させる。
        $calendarForm.Show(
            $popup
        )

        $calendarForm.Activate()
    })

    $buttonApply =
        New-Object System.Windows.Forms.Button

    $buttonApply.Text =
        "適用"

    $buttonApply.Font =
        $filterButtonFont

    $buttonApply.Location =
        New-Object System.Drawing.Point(157, 126)

    $buttonApply.Size =
        New-Object System.Drawing.Size(72, 28)

    $buttonClear =
        New-Object System.Windows.Forms.Button

    $buttonClear.Text =
        "解除"

    $buttonClear.Font =
        $filterButtonFont

    $buttonClear.Location =
        New-Object System.Drawing.Point(239, 126)

    $buttonClear.Size =
        New-Object System.Drawing.Size(72, 28)

    $buttonClose =
        New-Object System.Windows.Forms.Button

    $buttonClose.Text =
        "閉じる"

    $buttonClose.Font =
        $filterButtonFont

    $buttonClose.Location =
        New-Object System.Drawing.Point(321, 126)

    $buttonClose.Size =
        New-Object System.Drawing.Size(72, 28)

    # M16.8.15.5.3.4 v1.1
    # Tab順を動的入力欄の数に合わせて再構築する。
    $updateMultiValueTabOrder = {

        $tabIndex =
            0

        $comboCondition.TabIndex =
            $tabIndex

        $tabIndex++

        if (
            -not $isChoiceFilter -and
            -not $isBooleanFilter -and
            -not $isDateFilter
        ) {

            $textValue.TabIndex =
                $tabIndex

            $tabIndex++

            foreach (
                $rowState in @(
                    $multiValueRows
                )
            ) {

                if ($null -ne $rowState.TextBox) {

                    $rowState.TextBox.TabIndex =
                        $tabIndex

                    $rowState.TextBox.TabStop =
                        $true

                    $tabIndex++
                }
            }
        }
        elseif ($isChoiceFilter) {

            $choiceValue.TabIndex =
                $tabIndex

            $tabIndex++
        }
        elseif ($isBooleanFilter) {

            $booleanValue.TabIndex =
                $tabIndex

            $tabIndex++
        }
        elseif ($isDateFilter) {

            $dateValue.TabIndex =
                $tabIndex

            $tabIndex++
        }

        $buttonApply.TabIndex =
            $tabIndex

        $tabIndex++

        $buttonClear.TabIndex =
            $tabIndex

        $tabIndex++

        $buttonClose.TabIndex =
            $tabIndex
    }

    # M16.8.15.5.3.4 v2
    # Text列では、値が必要な全条件で複数値入力を使用する。
    $updateMultiValueLayout = {

        $condition =
            ConvertFrom-HashEditorFilterConditionDisplayText `
                -DisplayText ([string]$comboCondition.SelectedItem)

        $isTextFilter =
            (
                -not $isChoiceFilter -and
                -not $isBooleanFilter -and
                -not $isDateFilter
            )

        $needsValue =
            Test-HashEditorTextFilterNeedsValue `
                -Condition $condition

        $useMultiValueUi =
            (
                $isTextFilter -and
                $needsValue
            )

        if (-not $useMultiValueUi) {

            if ($isTextFilter) {
                $multiValueHint.Visible =
                    $false
            }

            $popup.ClientSize =
                New-Object System.Drawing.Size(
                    550,
                    166
                )

            $buttonY =
                126

            $buttonApply.Location =
                New-Object System.Drawing.Point(
                    157,
                    $buttonY
                )

            $buttonClear.Location =
                New-Object System.Drawing.Point(
                    239,
                    $buttonY
                )

            $buttonClose.Location =
                New-Object System.Drawing.Point(
                    321,
                    $buttonY
                )

            & $updateMultiValueTabOrder
            return
        }

        $multiValueHint.Visible =
            $true

        $rowIndex =
            0

        foreach (
            $rowState in @(
                $multiValueRows
            )
        ) {

            $rowNumber =
                $rowIndex + 2

            $rowY =
                66 + ($rowNumber - 1) * 35

            $rowState.Label.Text =
                "値" + [string]$rowNumber

            $rowState.Label.Location =
                New-Object System.Drawing.Point(
                    16,
                    ($rowY + 6)
                )

            $rowState.TextBox.Location =
                New-Object System.Drawing.Point(
                    92,
                    $rowY
                )

            $rowState.RemoveButton.Location =
                New-Object System.Drawing.Point(
                    460,
                    ($rowY - 3)
                )

            $rowIndex++
        }

        $extraHeight =
            $multiValueRows.Count * 35

        $hintY =
            92 + $extraHeight

        $multiValueHint.Location =
            New-Object System.Drawing.Point(
                92,
                $hintY
            )

        $buttonY =
            124 + $extraHeight

        $popup.ClientSize =
            New-Object System.Drawing.Size(
                550,
                (164 + $extraHeight)
            )

        $buttonApply.Location =
            New-Object System.Drawing.Point(
                157,
                $buttonY
            )

        $buttonClear.Location =
            New-Object System.Drawing.Point(
                239,
                $buttonY
            )

        $buttonClose.Location =
            New-Object System.Drawing.Point(
                321,
                $buttonY
            )

        & $updateMultiValueTabOrder
    }

    $buttonAddMultiValue.Add_Click({

        $rowLabel =
            New-Object System.Windows.Forms.Label

        $rowLabel.AutoSize =
            $true

        $rowLabel.Font =
            $filterFont

        # M16.8.15.5.3.4 v2.6
        # 値2以降も値1と同じ入力可能ComboBox。
        $rowTextBox =
            New-Object System.Windows.Forms.ComboBox

        $rowTextBox.DropDownStyle =
            [System.Windows.Forms.ComboBoxStyle]::DropDown

        $rowTextBox.AutoCompleteMode =
            [System.Windows.Forms.AutoCompleteMode]::SuggestAppend

        $rowTextBox.AutoCompleteSource =
            [System.Windows.Forms.AutoCompleteSource]::ListItems

        $rowTextBox.Font =
            $filterFont

        $rowTextBox.Size =
            New-Object System.Drawing.Size(
                364,
                32
            )

        foreach ($textFilterItem in @($textFilterItems)) {

            [void]$rowTextBox.Items.Add(
                [string]$textFilterItem
            )
        }

        Set-HashEditorFilterComboLimitNote `
            -ComboBox $rowTextBox

        $rowRemoveButton =
            New-Object System.Windows.Forms.Button

        $rowRemoveButton.Text =
            "-"

        $rowRemoveButton.Font =
            $filterButtonFont

        $rowRemoveButton.Size =
            New-Object System.Drawing.Size(
                32,
                28
            )

        $rowRemoveButton.TabStop =
            $false

        $rowState =
            @{
                Label        = $rowLabel
                TextBox      = $rowTextBox
                RemoveButton = $rowRemoveButton
            }

        $rowRemoveButton.Tag =
            $rowState

        $rowRemoveButton.Add_Click({

            param(
                $sender,
                $eventArgs
            )

            $target =
                $sender.Tag

            if ($null -eq $target) {
                return
            }

            [void]$multiValueRows.Remove(
                $target
            )

            foreach (
                $control in @(
                    $target.Label,
                    $target.TextBox,
                    $target.RemoveButton
                )
            ) {

                if ($null -ne $control) {
                    $popup.Controls.Remove(
                        $control
                    )
                    $control.Dispose()
                }
            }

            & $updateMultiValueLayout
        })

        [void]$multiValueRows.Add(
            $rowState
        )

        [void]$popup.Controls.Add(
            $rowLabel
        )

        [void]$popup.Controls.Add(
            $rowTextBox
        )

        [void]$popup.Controls.Add(
            $rowRemoveButton
        )

        & $updateMultiValueLayout

        [void]$rowTextBox.Focus()
    })

    $comboCondition.Add_SelectedIndexChanged({

        & $updateValueInputState
        & $updateMultiValueLayout
    })

    & $updateValueInputState
    & $updateMultiValueLayout

    # M16.8.15.5.3.4 v2
    # 保存済みText Filterは、条件を問わず2件目以降の値欄も復元する。
    if (
        $null -ne $savedFilterState -and
        -not $isChoiceFilter -and
        -not $isBooleanFilter -and
        -not $isDateFilter -and
        (
            Test-HashEditorTextFilterNeedsValue `
                -Condition ([string]$savedFilterState.Condition)
        )
    ) {

        $savedMultiValues =
            @(
                ConvertFrom-HashEditorMultiFilterValue `
                    -Value ([string]$savedFilterState.Value)
            )

        for (
            $savedIndex = 1;
            $savedIndex -lt $savedMultiValues.Count;
            $savedIndex++
        ) {

            $buttonAddMultiValue.PerformClick()

            if ($multiValueRows.Count -gt 0) {

                $multiValueRows[
                    $multiValueRows.Count - 1
                ].TextBox.Text =
                    [string]$savedMultiValues[$savedIndex]
            }
        }

        & $updateMultiValueLayout
    }

    $buttonApply.Add_Click({

        $filterValue =
            ""

        if ($isChoiceFilter) {

            if (
                $choiceValue.SelectedIndex -ge 0
            ) {

                $filterValue =
                    [string]$choiceValue.SelectedItem
            }
        }
        elseif ($isBooleanFilter) {

            if (
                $booleanValue.SelectedIndex -ge 0
            ) {

                $filterValue =
                    [string]$booleanValue.SelectedItem
            }
        }
        elseif ($isDateFilter) {

            $filterValue =
                [string]$dateValue.Text
        }
        else {

            $filterValue =
                [string]$textValue.Text
        }

        $filterCondition =
            ConvertFrom-HashEditorFilterConditionDisplayText `
                -DisplayText ([string]$comboCondition.SelectedItem)

        if (
            -not $isChoiceFilter -and
            -not $isBooleanFilter -and
            -not $isDateFilter -and
            (
                Test-HashEditorTextFilterNeedsValue `
                    -Condition $filterCondition
            )
        ) {

            $multiValues =
                New-Object System.Collections.ArrayList

            if (
                -not [string]::IsNullOrWhiteSpace(
                    [string]$textValue.Text
                )
            ) {

                [void]$multiValues.Add(
                    [string]$textValue.Text
                )
            }

            foreach (
                $rowState in @(
                    $multiValueRows
                )
            ) {

                if (
                    $null -ne $rowState.TextBox -and
                    -not [string]::IsNullOrWhiteSpace(
                        [string]$rowState.TextBox.Text
                    )
                ) {

                    [void]$multiValues.Add(
                        [string]$rowState.TextBox.Text
                    )
                }
            }

            $filterValue =
                ConvertTo-HashEditorMultiFilterValue `
                    -Values @($multiValues)
        }

        if (
            Invoke-HashEditorDisplayFilter `
                -Grid $Grid `
                -ColumnName $ColumnName `
                -Condition $filterCondition `
                -Value $filterValue
        ) {
            $popup.Close()
        }
    })

    $buttonClear.Add_Click({

        if (
            Test-HashEditorDisplayFilterActive
        ) {

            [void](
                Clear-HashEditorDisplayFilterColumn `
                    -Grid $Grid `
                    -ColumnName $ColumnName `
                    -Silent
            )
        }

        $popup.Close()
    })

    $buttonClose.Add_Click({
        $popup.Close()
    })

    $popup.AcceptButton =
        $buttonApply

    $popup.CancelButton =
        $buttonClose

    [void]$popup.Controls.Add($labelCondition)
    [void]$popup.Controls.Add($comboCondition)
    [void]$popup.Controls.Add($labelValue)
    [void]$popup.Controls.Add($textValue)
    [void]$popup.Controls.Add($buttonAddMultiValue)
    [void]$popup.Controls.Add($multiValueHint)
    [void]$popup.Controls.Add($choiceValue)
    [void]$popup.Controls.Add($booleanValue)
    [void]$popup.Controls.Add($dateValue)
    [void]$popup.Controls.Add($dateCalendarButton)
    [void]$popup.Controls.Add($dateNoteMark)
    [void]$popup.Controls.Add($dateInputHint)
    [void]$popup.Controls.Add($buttonApply)
    [void]$popup.Controls.Add($buttonClear)
    [void]$popup.Controls.Add($buttonClose)

    # M16.8.29.3.15
    # 正式仕様 COL-003: 対象列の3番目の表示データ行右端を基準にする。
    #
    # 縦:
    #   Popup上端 = 対象列の3番目の表示データ行セル上端
    #
    # 横:
    #   Popup左端 = 対象列右端 - 20px
    #
    # 表示データが3行未満の場合は、最後の表示データ行を基準にする。
    # データ行がない場合だけ、従来どおり列ヘッダー右端を基準にする。
    $targetColumn =
        $Grid.Columns[$ColumnName]

    $visibleDataRows =
        @(
            foreach ($gridRow in $Grid.Rows) {

                if (
                    $null -ne $gridRow -and
                    $gridRow.Visible -and
                    -not $gridRow.IsNewRow
                ) {
                    $gridRow
                }
            }
        )

    $targetRow =
        $null

    if ($visibleDataRows.Count -ge 3) {
        $targetRow =
            $visibleDataRows[2]
    }
    elseif ($visibleDataRows.Count -gt 0) {
        $targetRow =
            $visibleDataRows[$visibleDataRows.Count - 1]
    }

    if ($null -ne $targetRow) {

        $targetCellRect =
            $Grid.GetCellDisplayRectangle(
                $targetColumn.Index,
                $targetRow.Index,
                $true
            )

        $targetCellPoint =
            New-Object System.Drawing.Point(
                $targetCellRect.Right,
                $targetCellRect.Top
            )

        $targetScreenPoint =
            $Grid.PointToScreen(
                $targetCellPoint
            )

        $popupLocation =
            New-Object System.Drawing.Point(
                ($targetScreenPoint.X - 20),
                $targetScreenPoint.Y
            )
    }
    else {

        # データ行がない場合は対象列ヘッダー右端を基準にする。
        $headerRect =
            $Grid.GetCellDisplayRectangle(
                $targetColumn.Index,
                -1,
                $true
            )

        $headerPoint =
            New-Object System.Drawing.Point(
                $headerRect.Right,
                $headerRect.Bottom
            )

        $headerScreenPoint =
            $Grid.PointToScreen(
                $headerPoint
            )

        $popupLocation =
            New-Object System.Drawing.Point(
                ($headerScreenPoint.X - 20),
                $headerScreenPoint.Y
            )
    }

    # マルチモニターを含め、Popup全体が画面内に収まるよう補正する。
    $popupScreen =
        [System.Windows.Forms.Screen]::FromPoint(
            $popupLocation
        )

    $workingArea =
        $popupScreen.WorkingArea

    if ($popupLocation.X -lt $workingArea.Left) {
        $popupLocation.X =
            $workingArea.Left
    }

    if (
        (
            $popupLocation.X +
            $popup.Width
        ) -gt
        $workingArea.Right
    ) {

        $popupLocation.X =
            $workingArea.Right -
            $popup.Width
    }

    if ($popupLocation.Y -lt $workingArea.Top) {
        $popupLocation.Y =
            $workingArea.Top
    }

    if (
        (
            $popupLocation.Y +
            $popup.Height
        ) -gt
        $workingArea.Bottom
    ) {

        $popupLocation.Y =
            $workingArea.Bottom -
            $popup.Height
    }

    $popup.Location =
        $popupLocation

    $owner =
        $Grid.FindForm()

    if ($null -ne $owner) {
        [void]$popup.ShowDialog($owner)
    }
    else {
        [void]$popup.ShowDialog()
    }

    $popup.Dispose()
}