0

FlowDocumentPageViewer検索を作成し、指定されたリンクに似た を使用してテキストを強調表示しています。

http://kentb.blogspot.com/2009/06/search-and-highlight-text-in-arbitrary.html

(文字列のリストを使用して) 文字列のトークンを検索すると、すべてが正常に機能し、長方形が適切に適用されます。しかし、ここで2つの問題があります。

  1. のページを変更するFlowDocumentPageViewerと、長方形の強調表示された領域は同じままで、テキストが沈んでいません。

  2. をズームインまたはズームアウトするFlowDocumentPageViewerと、テキストはズームされますが、ハイライトの四角形は同じ位置に残ります。

この問題を解決して、長方形がテキスト自体に適用されるようにしてください。ここでアプリケーションを公開しています。さらに情報が必要な場合はお知らせください。

    <StackPanel Grid.Row="0" Orientation="Horizontal">
        <TextBox x:Name="_searchTextBox" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" Width="200" Height="20" Margin="2"/>
        <Button x:Name="_searchButton" Height="{Binding Height, ElementName=_searchTextBox}" Width="50" Content="GO">
            </Button>
            <Button x:Name="_listItems" Height="{Binding Height, ElementName=_searchTextBox}" Width="50" Content="List"/>
        </StackPanel>

    <Grid Grid.Row="1">
        <FlowDocumentPageViewer>
            <FlowDocument Foreground="Black" FontFamily="Arial">
                <Paragraph FontSize="11">
                    The following details have been details from Amazon to match your initial query.Some of the returned values may have been empty, so have been ommitted from theresults shown here.Also where there have been more than one value returned viathe Amazon Details, these to have beenomitted for the sake of keeping things simplefor this small demo application. Simple is good,when trying to show how something works
                </Paragraph>
            </FlowDocument>
        </FlowDocumentPageViewer>
    </Grid>

    <ItemsControl ItemsSource="{Binding SearchRectangles}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                    <Rectangle Fill="#99FFFF00" Width="{Binding Width}"  Height="{Binding Height}"  Tag="{Binding Text}"  MouseDown="Rectangle_MouseDown">
                        <Rectangle.Style>
                            <Style TargetType="{x:Type Rectangle}">
                                <Style.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="BitmapEffect">
                                            <Setter.Value>
                                                <OuterGlowBitmapEffect GlowColor="BurlyWood" GlowSize="7"/>
                                            </Setter.Value>
                                        </Setter>
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </Rectangle.Style>

                    </Rectangle>
                </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Top" Value="{Binding Top}"/>
                <Setter Property="Canvas.Left" Value="{Binding Left}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

</Grid>
</Grid>

public partial class Window1 : Window
{
    public static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register("SearchText",
                                            typeof(string),
                                            typeof(Window1));

    public static readonly DependencyProperty SearchRectanglesProperty = DependencyProperty.Register("SearchRectangles",
                    typeof(ICollection<SearchRectangle>),
                    typeof(Window1));



    public IList<string> SearchTokens { get; set; }


    public Window1()
    {
        InitializeComponent();

        SearchRectangles = new ObservableCollection<SearchRectangle>();

        _searchButton.Click += delegate
        {
            DoSearch();
        };

        _listItems.Click += delegate
        {
            SearchTokens = new List<string>();
            SearchTokens.Add("been");
            SearchTokens.Add("Amazon");
            SearchTokens.Add("following");              
            DoSearch(SearchTokens);

        };

        _searchTextBox.KeyDown += delegate(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                DoSearch();
            }
        };
    }


    public void DoSearch(IList<string> searchTokens)
    {

        SearchRectangles.Clear();

        if (searchTokens == null)
            return;

        foreach (string token in searchTokens)
        {
            SearchText = token;
            DoSearch();
        }
    }

    public string SearchText
    {
        get { return GetValue(SearchTextProperty) as string; }
        set { SetValue(SearchTextProperty, value); }
    }

    public ICollection<SearchRectangle> SearchRectangles
    {
        get { return GetValue(SearchRectanglesProperty) as ICollection<SearchRectangle>; }
        set { SetValue(SearchRectanglesProperty, value); }
    }

    private void DoSearch()
    {
        DoSearch(false);
    }

    private void DoSearch(bool clearExisting)
    {
        if( clearExisting == true ) 
            SearchRectangles.Clear();
        if (SearchText.Length == 0)
        {
            return;
        }

        DoSearch(this);
    }

    private void DoSearch(DependencyObject searchIn)
    {
        if (searchIn == null)
        {
            return;
        }

        var contentHost = searchIn as IContentHost;

        if (contentHost != null)
        {
            DoSearch(contentHost as UIElement, contentHost);
        }
        else
        {
            var documentViewerBase = searchIn as DocumentViewerBase;

            if (documentViewerBase != null)
            {
                //extract the content hosts from the document viewer
                foreach (var pageView in documentViewerBase.PageViews)
                {
                    contentHost = pageView.DocumentPage as IContentHost;

                    if (contentHost != null)
                    {
                        DoSearch(documentViewerBase, contentHost);
                    }
                }
            }
        }

        //recurse through children
        var childCount = VisualTreeHelper.GetChildrenCount(searchIn);

        for (var i = 0; i < childCount; ++i)
        {
            DoSearch(VisualTreeHelper.GetChild(searchIn, i));
        }
    }

    private void DoSearch(UIElement uiHost, IContentHost contentHost)
    {
        if (uiHost == null)
        {
            return;
        }

        var textBlock = contentHost as TextBlock;

        if (textBlock != null)
        {
            //this has the side affect of converting any plain string content in the TextBlock into a hosted Run element
            //that's bad in that it is unexpected, but good in that it allows us to access the hosted elements in a
            //consistent fashion below, rather than special-casing TextBlocks with text only content
            var contentStart = textBlock.ContentStart;
        }

        var hostedElements = contentHost.HostedElements;

        while (hostedElements.MoveNext())
        {
            var run = hostedElements.Current as Run;

            if (run != null && !string.IsNullOrEmpty(run.Text))
            {
                ApplyHighlighting(run.Text, delegate(int start, int length)
                {
                    var textPointer = run.ContentStart;
                    textPointer = textPointer.GetPositionAtOffset(start, LogicalDirection.Forward);
                    var leftRectangle = textPointer.GetCharacterRect(LogicalDirection.Forward);
                    textPointer = textPointer.GetPositionAtOffset(length, LogicalDirection.Forward);
                    var rightRectangle = textPointer.GetCharacterRect(LogicalDirection.Backward);
                    var rect = new Rect(leftRectangle.TopLeft, rightRectangle.BottomRight);
                    var translatedPoint = uiHost.TranslatePoint(new Point(0, 0), null);
                    rect.Offset(translatedPoint.X, translatedPoint.Y);
                    return rect;
                });

            }
        }
    }

    private void ApplyHighlighting(string text, Func<int, int, Rect> getRectHandler)
    {
        var currentIndex = 0;

        while (true)
        {
            var index = text.IndexOf(SearchText, currentIndex, StringComparison.CurrentCultureIgnoreCase);

            if (index == -1)
            {
                return;
            }

            var rect = getRectHandler(index, SearchText.Length);

            if (rect != Rect.Empty)
            {
                SearchRectangles.Add(new SearchRectangle(rect.Top, rect.Left, rect.Width, rect.Height,SearchText));
            }

            currentIndex = index + SearchText.Length;
        }
    }

    private void Rectangle_MouseDown(object sender, MouseEventArgs e)
    {
        Rectangle r = sender as Rectangle;
        MessageBox.Show(r.Tag.ToString());
    }

    private void FlowDocumentPageViewer_PageViewsChanged(object sender, EventArgs e)
    {

    }

    private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        DoSearch(SearchTokens);
    }

}

public class SearchRectangle
{
    private readonly double _top;
    private readonly double _left;
    private readonly double _width;
    private readonly double _height;
    private readonly string _text;

    public SearchRectangle(double top, double left, double width, double height,string text)
    {
        _top = top;
        _left = left;
        _width = width;
        _height = height;
        _text = text;

    }

    public string Text
    {
        get { return _text; }
    }

    public double Top
    {
        get { return _top; }
    }

    public double Left
    {
        get { return _left; }
    }

    public double Width
    {
        get { return _width; }
    }

    public double Height
    {
        get { return _height; }
    }
}

一番、

バラ。

4

2 に答える 2

0

簡単な解決策のように見えるのは、実際にドキュメントを編集して検索時に強調表示を行うことです。検索結果をクリアしたり、他の目的 (保存など) で未編集のドキュメントが必要になった場合は、ドキュメントを元に戻すことを忘れないでください。

この回答に投稿したコードを使用して、ドキュメントのテキストを検索できます。あなたの場合、見つかった各範囲に選択を設定する代わりに、次のように範囲を強調表示する必要があります。

public void HilightMatches(TextRange searchRange, string searchText)
{
  var start = searchRange.Start;
  while(start != searchRange.End)
  {
    var foundRange = FindTextInRange(
      new TextRange(start, searchRange.End),
      searchText);

    if(foundRange==null) return;
    // Here is the meat...
    foundRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Yellow);
    start = foundRange.End;
  }
}

写真を完成させるには、作業が終わったらハイライトをクリアする方法が必要です。いくつかのオプション:

  1. ハイライトされた範囲を保存して、ApplyPropertyValue を使用して Brushes.Transparent 背景を適用できるようにします (単純ですが、これにより、以前に設定された背景がすべて消去されます)。

  2. 見つかった各範囲をランに分割し、ランのリストをそれぞれ元の背景色で保存するので、簡単に復元できます

  3. いじる前にドキュメント全体を保存し、それを復元してハイライトを削除します

  4. ドキュメントが RichTextBox にあり、ユーザーがドキュメントの編集を許可されていない場合は、単純に元に戻すメカニズムを使用できます。ハイライトを行うときに TextBoxBase.UndoLimit が増加していることを確認してから、ハイライトを削除するには、ハイライトごとに 1 回 TextBoxBase.Undo() を呼び出します。

于 2009-11-19T08:25:09.250 に答える
0

この解決策を試してみてください http://rredcat.blogspot.com/2009/11/zoom-and-page-chahged-events-for.html

于 2009-11-20T00:28:02.050 に答える