次の方法で共有


UI オートメーションを使用した、テキストの検索と強調表示

Note

このドキュメントは、System.Windows.Automation 名前空間で定義されているマネージド UI オートメーション クラスを使用する .NET Framework 開発者を対象としています。 UI オートメーションの最新情報については、Windows Automation API の「UI オートメーション」を参照してください。

このトピックでは、Microsoft UI オートメーションを使用して、テキスト コントロールのコンテンツ内の文字列の各出現箇所を順次検索し、強調表示する方法を示します。

次の例では、テキスト コントロールから TextPattern オブジェクトを取得します。 その後、ドキュメント全体のテキスト コンテンツを表す TextPatternRange オブジェクトが、この TextPatternDocumentRange プロパティを使用して作成されます。 その後、順次検索と強調表示の機能に対して、2 つの TextPatternRange オブジェクトが追加で作成されます。

///--------------------------------------------------------------------
/// <summary>
/// Starts the target application.
/// </summary>
/// <param name="app">
/// The application to start.
/// </param>
/// <returns>The automation element for the app main window.</returns>
/// <remarks>
/// Three WPF documents, a rich text document, and a plain text document
/// are provided in the Content folder of the TextProvider project.
/// </remarks>
///--------------------------------------------------------------------
private AutomationElement StartApp(string app)
{
    // Start application.
    Process p = Process.Start(app);

    // Give the target application some time to start.
    // For Win32 applications, WaitForInputIdle can be used instead.
    // Another alternative is to listen for WindowOpened events.
    // Otherwise, an ArgumentException results when you try to
    // retrieve an automation element from the window handle.
    Thread.Sleep(2000);

    targetResult.Content =
        WPFTarget +
        " started. \n\nPlease load a document into the target " +
        "application and click the 'Find edit control' button above. " +
        "\n\nNOTE: Documents can be found in the 'Content' folder of the FindText project.";
    targetResult.Background = Brushes.LightGreen;

    // Return the automation element for the app main window.
    return (AutomationElement.FromHandle(p.MainWindowHandle));
}
'--------------------------------------------------------------------
' Starts the target application.
' <param name="app">
' The application to start.
' <returns>The automation element for the app main window.</returns>
' Three WPF documents, a rich text document, and a plain text document
' are provided in the Content folder of the TextProvider project.
'--------------------------------------------------------------------
Private Function StartApp(ByVal app As String) As AutomationElement
    ' Start application.
    Dim p As Process = Process.Start(app)

    ' Give the target application some time to start.
    ' For Win32 applications, WaitForInputIdle can be used instead.
    ' Another alternative is to listen for WindowOpened events.
    ' Otherwise, an ArgumentException results when you try to
    ' retrieve an automation element from the window handle.
    Thread.Sleep(2000)

    targetResult.Content = WPFTarget + " started. " + vbLf + vbLf + _
    "Please load a document into the target application and click " + _
    "the 'Find edit control' button above. " + vbLf + vbLf + _
    "NOTE: Documents can be found in the 'Content' folder of the FindText project."
    targetResult.Background = Brushes.LightGreen

    ' Return the automation element for the app main window.
    Return AutomationElement.FromHandle(p.MainWindowHandle)

End Function 'StartApp
///--------------------------------------------------------------------
/// <summary>
/// Finds the text control in our target.
/// </summary>
/// <param name="src">The object that raised the event.</param>
/// <param name="e">Event arguments.</param>
/// <remarks>
/// Initializes the TextPattern object and event handlers.
/// </remarks>
///--------------------------------------------------------------------
private void FindTextProvider_Click(object src, RoutedEventArgs e)
{
    // Set up the conditions for finding the text control.
    PropertyCondition documentControl = new PropertyCondition(
        AutomationElement.ControlTypeProperty,
        ControlType.Document);
    PropertyCondition textPatternAvailable = new PropertyCondition(
        AutomationElement.IsTextPatternAvailableProperty, true);
    AndCondition findControl =
        new AndCondition(documentControl, textPatternAvailable);

    // Get the Automation Element for the first text control found.
    // For the purposes of this sample it is sufficient to find the
    // first text control. In other cases there may be multiple text
    // controls to sort through.
    targetDocument =
        targetWindow.FindFirst(TreeScope.Descendants, findControl);

    // Didn't find a text control.
    if (targetDocument == null)
    {
        targetResult.Content =
            WPFTarget +
            " does not contain a Document control type.";
        targetResult.Background = Brushes.Salmon;
        startWPFTargetButton.IsEnabled = false;
        return;
    }

    // Get required control patterns
    targetTextPattern =
        targetDocument.GetCurrentPattern(
        TextPattern.Pattern) as TextPattern;

    // Didn't find a text control that supports TextPattern.
    if (targetTextPattern == null)
    {
        targetResult.Content =
            WPFTarget +
            " does not contain an element that supports TextPattern.";
        targetResult.Background = Brushes.Salmon;
        startWPFTargetButton.IsEnabled = false;
        return;
    }

    // Text control is available so display the client controls.
    infoGrid.Visibility = Visibility.Visible;

    targetResult.Content =
        "Text provider found.";
    targetResult.Background = Brushes.LightGreen;

    // Initialize the document range for the text of the document.
    documentRange = targetTextPattern.DocumentRange;

    // Initialize the client's search buttons.
    if (targetTextPattern.DocumentRange.GetText(1).Length > 0)
    {
        searchForwardButton.IsEnabled = true;
    }
    // Initialize the client's search TextBox.
    searchString.IsEnabled = true;

    // Check if the text control supports text selection
    if (targetTextPattern.SupportedTextSelection ==
        SupportedTextSelection.None)
    {
        targetResult.Content = "Unable to select text.";
        targetResult.Background = Brushes.Salmon;
        return;
    }

    // Edit control found so remove the find button from the client.
    findEditButton.Visibility = Visibility.Collapsed;

    // Initialize the client with the current target selection, if any.
    NotifySelectionChanged();

    // Search starts at beginning of doc and goes forward
    searchBackward = false;

    // Initialize a text changed listener.
    // An instance of TextPatternRange will become invalid if
    // one of the following occurs:
    // 1) The text in the provider changes via some user activity.
    // 2) ValuePattern.SetValue is used to programmatically change
    // the value of the text in the provider.
    // The only way the client application can detect if the text
    // has changed (to ensure that the ranges are still valid),
    // is by setting a listener for the TextChanged event of
    // the TextPattern. If this event is raised, the client needs
    // to update the targetDocumentRange member data to ensure the
    // user is working with the updated text.
    // Clients must always anticipate the possibility that the text
    // can change underneath them.
    Automation.AddAutomationEventHandler(
        TextPattern.TextChangedEvent,
        targetDocument,
        TreeScope.Element,
        TextChanged);

    // Initialize a selection changed listener.
    // The target selection is reflected in the client.
    Automation.AddAutomationEventHandler(
        TextPattern.TextSelectionChangedEvent,
        targetDocument,
        TreeScope.Element,
        OnTextSelectionChange);
}
'--------------------------------------------------------------------
' Finds the text control in our target.
' <param name="src">The object that raised the event.</param>
' <param name="e">Event arguments.</param>
' Initializes the TextPattern object and event handlers.
'--------------------------------------------------------------------
Private Sub FindTextProvider_Click( _
ByVal src As Object, ByVal e As RoutedEventArgs)
    ' Set up the conditions for finding the text control.
    Dim documentControl As New PropertyCondition( _
    AutomationElement.ControlTypeProperty, ControlType.Document)
    Dim textPatternAvailable As New PropertyCondition( _
    AutomationElement.IsTextPatternAvailableProperty, True)
    Dim findControl As New AndCondition(documentControl, textPatternAvailable)

    ' Get the Automation Element for the first text control found.
    ' For the purposes of this sample it is sufficient to find the
    ' first text control. In other cases there may be multiple text
    ' controls to sort through.
    targetDocument = targetWindow.FindFirst(TreeScope.Descendants, findControl)

    ' Didn't find a text control.
    If targetDocument Is Nothing Then
        targetResult.Content = _
        WPFTarget + " does not contain a Document control type."
        targetResult.Background = Brushes.Salmon
        startWPFTargetButton.IsEnabled = False
        Return
    End If

    ' Get required control patterns
    targetTextPattern = DirectCast( _
    targetDocument.GetCurrentPattern(TextPattern.Pattern), TextPattern)

    ' Didn't find a text control that supports TextPattern.
    If targetTextPattern Is Nothing Then
        targetResult.Content = WPFTarget + _
        " does not contain an element that supports TextPattern."
        targetResult.Background = Brushes.Salmon
        startWPFTargetButton.IsEnabled = False
        Return
    End If
    ' Text control is available so display the client controls.
    infoGrid.Visibility = Visibility.Visible

    targetResult.Content = "Text provider found."
    targetResult.Background = Brushes.LightGreen

    ' Initialize the document range for the text of the document.
    documentRange = targetTextPattern.DocumentRange

    ' Initialize the client's search buttons.
    If targetTextPattern.DocumentRange.GetText(1).Length > 0 Then
        searchForwardButton.IsEnabled = True
    End If
    ' Initialize the client's search TextBox.
    searchString.IsEnabled = True

    ' Check if the text control supports text selection
    If targetTextPattern.SupportedTextSelection = SupportedTextSelection.None Then
        targetResult.Content = "Unable to select text."
        targetResult.Background = Brushes.Salmon
        Return
    End If

    ' Edit control found so remove the find button from the client.
    findEditButton.Visibility = Visibility.Collapsed

    ' Initialize the client with the current target selection, if any.
    NotifySelectionChanged()

    ' Search starts at beginning of doc and goes forward
    searchBackward = False

    ' Initialize a text changed listener.
    ' An instance of TextPatternRange will become invalid if
    ' one of the following occurs:
    ' 1) The text in the provider changes via some user activity.
    ' 2) ValuePattern.SetValue is used to programmatically change
    ' the value of the text in the provider.
    ' The only way the client application can detect if the text
    ' has changed (to ensure that the ranges are still valid),
    ' is by setting a listener for the TextChanged event of
    ' the TextPattern. If this event is raised, the client needs
    ' to update the targetDocumentRange member data to ensure the
    ' user is working with the updated text.
    ' Clients must always anticipate the possibility that the text
    ' can change underneath them.
    Dim onTextChanged As AutomationEventHandler = _
    New AutomationEventHandler(AddressOf TextChanged)
    Automation.AddAutomationEventHandler( _
    TextPattern.TextChangedEvent, targetDocument, TreeScope.Element, onTextChanged)
    ' Initialize a selection changed listener.
    ' The target selection is reflected in the client.
    Dim onSelectionChanged As AutomationEventHandler = _
    New AutomationEventHandler(AddressOf OnTextSelectionChange)
    Automation.AddAutomationEventHandler( _
    TextPattern.TextSelectionChangedEvent, targetDocument, _
    TreeScope.Element, onSelectionChanged)

End Sub
///--------------------------------------------------------------------
/// <summary>
/// Handles changes to the search text in the client.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">Event arguments.</param>
/// <remarks>
/// Reset all controls if user changes search text
/// </remarks>
///--------------------------------------------------------------------
void SearchString_Change(object sender, TextChangedEventArgs e)
{
    int startPoints = documentRange.CompareEndpoints(
        TextPatternRangeEndpoint.Start,
        searchRange,
        TextPatternRangeEndpoint.Start);
    int endPoints = documentRange.CompareEndpoints(
        TextPatternRangeEndpoint.End,
        searchRange,
        TextPatternRangeEndpoint.End);

    // If the starting endpoints of the document range and the search
    // range are equivalent then we can search forward only since the
    // search range is at the start of the document.
    if (startPoints == 0)
    {
        searchForwardButton.IsEnabled = true;
        searchBackwardButton.IsEnabled = false;
    }
    // If the ending endpoints of the document range and the search
    // range are identical then we can search backward only since the
    // search range is at the end of the document.
    else if (endPoints == 0)
    {
        searchForwardButton.IsEnabled = false;
        searchBackwardButton.IsEnabled = true;
    }
    // Otherwise we can search both directions.
    else
    {
        searchForwardButton.IsEnabled = true;
        searchBackwardButton.IsEnabled = true;
    }
}

///--------------------------------------------------------------------
/// <summary>
/// Handles the Search button click.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">Event arguments.</param>
/// <remarks>Find the text specified in the text box.</remarks>
///--------------------------------------------------------------------
void SearchDirection_Click(object sender, RoutedEventArgs e)
{
    Button searchDirection = (Button)sender;

    // Are we searching backward through the text control?
    searchBackward =
        ((traversalDirection)searchDirection.Tag == traversalDirection.Backward);

    // Check if search text entered
    if (searchString.Text.Trim() == "")
    {
        targetResult.Content = "No search criteria.";
        targetResult.Background = Brushes.Salmon;
        return;
    }

    // Does target range support text selection?
    if (targetTextPattern.SupportedTextSelection ==
        SupportedTextSelection.None)
    {
        targetResult.Content = "Unable to select text.";
        targetResult.Background = Brushes.Salmon;
        return;
    }
    // Does target range support multiple selections?
    if (targetTextPattern.SupportedTextSelection ==
        SupportedTextSelection.Multiple)
    {
        targetResult.Content = "Multiple selections present.";
        targetResult.Background = Brushes.Salmon;
        return;
    }

    // Clone the document range since we modify the endpoints
    // as we search.
    TextPatternRange documentRangeClone = documentRange.Clone();

    // Move the cloned document range endpoints to enable the
    // selection of the next matching text range.
    TextPatternRange[] selectionRange =
        targetTextPattern.GetSelection();
    if (selectionRange[0] != null)
    {
        if (searchBackward)
        {
            documentRangeClone.MoveEndpointByRange(
                TextPatternRangeEndpoint.End,
                selectionRange[0],
                TextPatternRangeEndpoint.Start);
        }
        else
        {
            documentRangeClone.MoveEndpointByRange(
                TextPatternRangeEndpoint.Start,
                selectionRange[0],
                TextPatternRangeEndpoint.End);
        }
    }

    // Find the text specified in the Search textbox.
    // Clone the search range since we need to modify it.
    TextPatternRange searchRangeClone = searchRange.Clone();
    // backward = false? -- search forward, otherwise backward.
    // ignoreCase = false? -- search is case sensitive.
    searchRange =
        documentRangeClone.FindText(
        searchString.Text, searchBackward, false);

    // Search unsuccessful.
    if (searchRange == null)
    {
        // Search string not found at all.
        if (documentRangeClone.CompareEndpoints(
            TextPatternRangeEndpoint.Start,
            searchRangeClone,
            TextPatternRangeEndpoint.Start) == 0)
        {
            targetResult.Content = "Text not found.";
            targetResult.Background = Brushes.Wheat;
            searchBackwardButton.IsEnabled = false;
            searchForwardButton.IsEnabled = false;
        }
        // End of document (either the start or end of the document
        // range depending on search direction) was reached before
        // finding another occurrence of the search string.
        else
        {
            targetResult.Content = "End of document reached.";
            targetResult.Background = Brushes.Wheat;
            if (!searchBackward)
            {
                searchRangeClone.MoveEndpointByRange(
                    TextPatternRangeEndpoint.Start,
                    documentRange,
                    TextPatternRangeEndpoint.End);
                searchBackwardButton.IsEnabled = true;
                searchForwardButton.IsEnabled = false;
            }
            else
            {
                searchRangeClone.MoveEndpointByRange(
                    TextPatternRangeEndpoint.End,
                    documentRange,
                    TextPatternRangeEndpoint.Start);
                searchBackwardButton.IsEnabled = false;
                searchForwardButton.IsEnabled = true;
            }
        }
        searchRange = searchRangeClone;
    }
    // The search string was found.
    else
    {
        targetResult.Content = "Text found.";
        targetResult.Background = Brushes.LightGreen;
    }

    searchRange.Select();
    // Scroll the selection into view and align with top of viewport
    searchRange.ScrollIntoView(true);
    // The WPF target doesn't show selected text as highlighted unless
    // the window has focus.
    targetWindow.SetFocus();
}
'--------------------------------------------------------------------
' Handles changes to the search text in the client.
' <param name="sender">The object that raised the event.</param>
' <param name="e">Event arguments.</param>
' Reset all controls if user changes search text
'--------------------------------------------------------------------
Private Sub SearchString_Change( _
ByVal sender As Object, ByVal e As TextChangedEventArgs)
    Dim startPoints As Integer = _
    documentRange.CompareEndpoints( _
    TextPatternRangeEndpoint.Start, searchRange, _
    TextPatternRangeEndpoint.Start)
    Dim endPoints As Integer = _
    documentRange.CompareEndpoints(TextPatternRangeEndpoint.End, _
    searchRange, TextPatternRangeEndpoint.End)

    ' If the starting endpoints of the document range and the search
    ' range are equivalent then we can search forward only since the
    ' search range is at the start of the document.
    If startPoints = 0 Then
        searchForwardButton.IsEnabled = True
        searchBackwardButton.IsEnabled = False
        ' If the ending endpoints of the document range and the search
        ' range are identical then we can search backward only since the
        ' search range is at the end of the document.
    ElseIf endPoints = 0 Then
        searchForwardButton.IsEnabled = False
        searchBackwardButton.IsEnabled = True
        ' Otherwise we can search both directions.
    Else
        searchForwardButton.IsEnabled = True
        searchBackwardButton.IsEnabled = True
    End If

End Sub

'--------------------------------------------------------------------
' Handles the Search button click.
' <param name="sender">The object that raised the event.</param>
' <param name="e">Event arguments.</param>
' <remarks>Find the text specified in the text box.</remarks>
'--------------------------------------------------------------------
Private Sub SearchDirection_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim searchDirection As Button = CType(sender, Button)

    ' Are we searching backward through the text control?
    searchBackward = _
    (CType(searchDirection.Tag, traversalDirection) = traversalDirection.Backward)

    ' Check if search text entered
    If searchString.Text.Trim() = "" Then
        targetResult.Content = "No search criteria."
        targetResult.Background = Brushes.Salmon
        Return
    End If

    ' Does target range support text selection?
    If targetTextPattern.SupportedTextSelection = SupportedTextSelection.None Then
        targetResult.Content = "Unable to select text."
        targetResult.Background = Brushes.Salmon
        Return
    End If
    ' Does target range support multiple selections?
    If targetTextPattern.SupportedTextSelection = SupportedTextSelection.Multiple Then
        targetResult.Content = "Multiple selections present."
        targetResult.Background = Brushes.Salmon
        Return
    End If
    ' Clone the document range since we modify the endpoints
    ' as we search.
    Dim documentRangeClone As TextPatternRange = documentRange.Clone()

    ' Move the cloned document range endpoints to enable the
    ' selection of the next matching text range.
    Dim selectionRange As TextPatternRange() = targetTextPattern.GetSelection()
    If Not (selectionRange(0) Is Nothing) Then
        If searchBackward Then
            documentRangeClone.MoveEndpointByRange( _
            TextPatternRangeEndpoint.End, selectionRange(0), _
            TextPatternRangeEndpoint.Start)
        Else
            documentRangeClone.MoveEndpointByRange( _
            TextPatternRangeEndpoint.Start, selectionRange(0), _
            TextPatternRangeEndpoint.End)
        End If
    End If

    ' Find the text specified in the Search textbox.
    ' Clone the search range since we need to modify it.
    Dim searchRangeClone As TextPatternRange = searchRange.Clone()
    ' backward = false? -- search forward, otherwise backward.
    ' ignoreCase = false? -- search is case sensitive.
    searchRange = documentRangeClone.FindText(searchString.Text, searchBackward, False)

    ' Search unsuccessful.
    If searchRange Is Nothing Then
        ' Search string not found at all.
        If documentRangeClone.CompareEndpoints( _
        TextPatternRangeEndpoint.Start, searchRangeClone, _
        TextPatternRangeEndpoint.Start) = 0 Then
            targetResult.Content = "Text not found."
            targetResult.Background = Brushes.Wheat
            searchBackwardButton.IsEnabled = False
            searchForwardButton.IsEnabled = False
        Else
            ' End of document (either the start or end of the document
            ' range depending on search direction) was reached before
            ' finding another occurrence of the search string.
            targetResult.Content = "End of document reached."
            targetResult.Background = Brushes.Wheat
            If Not searchBackward Then
                searchRangeClone.MoveEndpointByRange( _
                TextPatternRangeEndpoint.Start, documentRange, _
                TextPatternRangeEndpoint.End)
                searchBackwardButton.IsEnabled = True
                searchForwardButton.IsEnabled = False
            Else
                searchRangeClone.MoveEndpointByRange( _
                TextPatternRangeEndpoint.End, documentRange, _
                TextPatternRangeEndpoint.Start)
                searchBackwardButton.IsEnabled = False
                searchForwardButton.IsEnabled = True
            End If
        End If
        searchRange = searchRangeClone
    Else
        ' The search string was found.
        targetResult.Content = "Text found."
        targetResult.Background = Brushes.LightGreen
    End If

    searchRange.Select()
    ' Scroll the selection into view and align with top of viewport
    searchRange.ScrollIntoView(True)
    ' The WPF target doesn't show selected text as highlighted unless
    ' the window has focus.
    targetWindow.SetFocus()

End Sub

関連項目