在RichEditBox中保持选择的视觉效果是不重点?

时间:2014-08-04 15:56:30

标签: c# windows-runtime winrt-xaml richeditbox

有人知道如何在RichEditBox中保持所选文本的视觉选择状态吗?我想在我的Windows 8.1应用程序中添加一些基本的文本编辑,但每次选择文本并单击应用程序中的另一个UI元素时,RichEditBox都会隐藏选择。

我已经尝试注册非聚焦事件,再次设置选择范围,但不幸的是,这没有效果。

我还尝试使用

在Text上绘制自己的rect
richEdit.Document.Selection.GetRect(PointOptions.ClientCoordinates,out selectionRect, out hitCount );

只要选择了一行中的某些文本,就可以正常工作。如果选择是多行的,我只获得所选文本的左上角和右下角。看起来这些是鼠标位置选择开始位置和结束位置。

当RichEditBox未聚焦时,还有其他方法可以保持所选文本的可见性。

2 个答案:

答案 0 :(得分:1)

我发现了另一种解决方法。只需在RichEditBox未聚焦时设置选择背景。但是Jerry的帖子给了我这个解决方案的灵感。似乎这样简单地找到它是第一位的:

private void RichEditOnGotFocus(object sender, RoutedEventArgs routedEventArgs)
{
    ITextSelection selectedText = richEdit.Document.Selection;
    if (selectedText != null)
    {
        richEdit.Document.Selection.SetRange(_selectionStart, _selectionEnd);
        selectedText.CharacterFormat.BackgroundColor = Colors.White;
    }
}

private void RichEditOnLostFocus(object sender, RoutedEventArgs routedEventArgs)
{
    _selectionEnd = richEdit.Document.Selection.EndPosition;
    _selectionStart = richEdit.Document.Selection.StartPosition;

    ITextSelection selectedText = richEdit.Document.Selection;
    if (selectedText != null)
    {
        selectedText.CharacterFormat.BackgroundColor = Colors.Gray;
    }
}

答案 1 :(得分:0)

在WinRT工具包中,有一个HighlightBehavior并没有直接解决您的问题,但可能会为您提供一个可接受的解决方案。

http://winrtxamltoolkit.codeplex.com/SourceControl/latest#WinRTXamlToolkit/WinRTXamlToolkit.Shared/Controls/Behaviors/HighlightBehavior.cs

public class HighlightBehavior : Behavior<TextBlock>
{
    #region SearchString
    /// <summary>
    /// SearchString Dependency Property
    /// </summary>
    public static readonly DependencyProperty SearchStringProperty =
        DependencyProperty.Register(
            "SearchString",
            typeof(string),
            typeof(HighlightBehavior),
            new PropertyMetadata(null, OnSearchStringChanged));

    /// <summary>
    /// Gets or sets the SearchString property. This dependency property 
    /// indicates the search string to highlight in the associated TextBlock.
    /// </summary>
    public string SearchString
    {
        get { return (string)GetValue(SearchStringProperty); }
        set { SetValue(SearchStringProperty, value); }
    }

    /// <summary>
    /// Handles changes to the SearchString property.
    /// </summary>
    /// <param name="d">
    /// The <see cref="DependencyObject"/> on which
    /// the property has changed value.
    /// </param>
    /// <param name="e">
    /// Event data that is issued by any event that
    /// tracks changes to the effective value of this property.
    /// </param>
    private static void OnSearchStringChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (HighlightBehavior)d;
        string oldSearchString = (string)e.OldValue;
        string newSearchString = target.SearchString;
        target.OnSearchStringChanged(oldSearchString, newSearchString);
    }

    /// <summary>
    /// Provides derived classes an opportunity to handle changes
    /// to the SearchString property.
    /// </summary>
    /// <param name="oldSearchString">The old SearchString value</param>
    /// <param name="newSearchString">The new SearchString value</param>
    private void OnSearchStringChanged(
        string oldSearchString, string newSearchString)
    {
        UpdateHighlight();
    }
    #endregion

    #region IsCaseSensitive
    /// <summary>
    /// IsCaseSensitive Dependency Property
    /// </summary>
    public static readonly DependencyProperty IsCaseSensitiveProperty =
        DependencyProperty.Register(
            "IsCaseSensitive",
            typeof(bool),
            typeof(HighlightBehavior),
            new PropertyMetadata(false, OnIsCaseSensitiveChanged));

    /// <summary>
    /// Gets or sets the IsCaseSensitive property. This dependency property 
    /// indicates whether the highlight behavior is case sensitive.
    /// </summary>
    public bool IsCaseSensitive
    {
        get { return (bool)GetValue(IsCaseSensitiveProperty); }
        set { SetValue(IsCaseSensitiveProperty, value); }
    }

    /// <summary>
    /// Handles changes to the IsCaseSensitive property.
    /// </summary>
    /// <param name="d">
    /// The <see cref="DependencyObject"/> on which
    /// the property has changed value.
    /// </param>
    /// <param name="e">
    /// Event data that is issued by any event that
    /// tracks changes to the effective value of this property.
    /// </param>
    private static void OnIsCaseSensitiveChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (HighlightBehavior)d;
        bool oldIsCaseSensitive = (bool)e.OldValue;
        bool newIsCaseSensitive = target.IsCaseSensitive;
        target.OnIsCaseSensitiveChanged(oldIsCaseSensitive, newIsCaseSensitive);
    }

    /// <summary>
    /// Provides derived classes an opportunity to handle changes
    /// to the IsCaseSensitive property.
    /// </summary>
    /// <param name="oldIsCaseSensitive">The old IsCaseSensitive value</param>
    /// <param name="newIsCaseSensitive">The new IsCaseSensitive value</param>
    private void OnIsCaseSensitiveChanged(
        bool oldIsCaseSensitive, bool newIsCaseSensitive)
    {
        UpdateHighlight();
    }
    #endregion

    #region HighlightTemplate
    /// <summary>
    /// HighlightTemplate Dependency Property
    /// </summary>
    public static readonly DependencyProperty HighlightTemplateProperty =
        DependencyProperty.Register(
            "HighlightTemplate",
            typeof(DataTemplate),
            typeof(HighlightBehavior),
            new PropertyMetadata(null, OnHighlightTemplateChanged));

    /// <summary>
    /// Gets or sets the HighlightTemplate property. This dependency property 
    /// indicates the template to use to generate the highlight Run inlines.
    /// </summary>
    public DataTemplate HighlightTemplate
    {
        get { return (DataTemplate)GetValue(HighlightTemplateProperty); }
        set { SetValue(HighlightTemplateProperty, value); }
    }

    /// <summary>
    /// Handles changes to the HighlightTemplate property.
    /// </summary>
    /// <param name="d">
    /// The <see cref="DependencyObject"/> on which
    /// the property has changed value.
    /// </param>
    /// <param name="e">
    /// Event data that is issued by any event that
    /// tracks changes to the effective value of this property.
    /// </param>
    private static void OnHighlightTemplateChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (HighlightBehavior)d;
        DataTemplate oldHighlightTemplate = (DataTemplate)e.OldValue;
        DataTemplate newHighlightTemplate = target.HighlightTemplate;
        target.OnHighlightTemplateChanged(oldHighlightTemplate, newHighlightTemplate);
    }

    /// <summary>
    /// Provides derived classes an opportunity to handle changes
    /// to the HighlightTemplate property.
    /// </summary>
    /// <param name="oldHighlightTemplate">The old HighlightTemplate value</param>
    /// <param name="newHighlightTemplate">The new HighlightTemplate value</param>
    private void OnHighlightTemplateChanged(
        DataTemplate oldHighlightTemplate, DataTemplate newHighlightTemplate)
    {
        UpdateHighlight();
    }
    #endregion

    #region HighlightBrush
    /// <summary>
    /// HighlightBrush Dependency Property
    /// </summary>
    public static readonly DependencyProperty HighlightBrushProperty =
        DependencyProperty.Register(
            "HighlightBrush",
            typeof(Brush),
            typeof(HighlightBehavior),
            new PropertyMetadata(new SolidColorBrush(Colors.Red), OnHighlightBrushChanged));

    /// <summary>
    /// Gets or sets the HighlightBrush property. This dependency property 
    /// indicates the brush to use to highlight the found instances of the search string.
    /// </summary>
    /// <remarks>
    /// Note that the brush is ignored if HighlightTemplate is specified
    /// </remarks>
    public Brush HighlightBrush
    {
        get { return (Brush)GetValue(HighlightBrushProperty); }
        set { SetValue(HighlightBrushProperty, value); }
    }

    /// <summary>
    /// Handles changes to the HighlightBrush property.
    /// </summary>
    /// <param name="d">
    /// The <see cref="DependencyObject"/> on which
    /// the property has changed value.
    /// </param>
    /// <param name="e">
    /// Event data that is issued by any event that
    /// tracks changes to the effective value of this property.
    /// </param>
    private static void OnHighlightBrushChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (HighlightBehavior)d;
        Brush oldHighlightBrush = (Brush)e.OldValue;
        Brush newHighlightBrush = target.HighlightBrush;
        target.OnHighlightBrushChanged(oldHighlightBrush, newHighlightBrush);
    }

    /// <summary>
    /// Provides derived classes an opportunity to handle changes
    /// to the HighlightBrush property.
    /// </summary>
    /// <param name="oldHighlightBrush">The old HighlightBrush value</param>
    /// <param name="newHighlightBrush">The new HighlightBrush value</param>
    private void OnHighlightBrushChanged(
        Brush oldHighlightBrush, Brush newHighlightBrush)
    {
        UpdateHighlight();
    }
    #endregion

    private PropertyChangeEventSource<string> _textChangeEventSource;

    /// <summary>
    /// Called after the behavior is attached to an AssociatedObject.
    /// </summary>
    /// <remarks>
    /// Override this to hook up functionality to the AssociatedObject.
    /// </remarks>
    protected override void OnAttached()
    {
        UpdateHighlight();
        _textChangeEventSource = new PropertyChangeEventSource<string>(this.AssociatedObject, "Text", BindingMode.OneWay);
        _textChangeEventSource.ValueChanged += TextChanged;
        base.OnAttached();
    }

    /// <summary>
    /// Called when the behavior is being detached from its AssociatedObject, but
    /// before it has actually occurred.
    /// </summary>
    /// <remarks>
    /// Override this to unhook functionality from the AssociatedObject.
    /// </remarks>
    protected override void OnDetaching()
    {
        ClearHighlight();
        _textChangeEventSource.ValueChanged -= TextChanged;
        _textChangeEventSource = null;
        base.OnDetaching();
    }

    private void TextChanged(object sender, string s)
    {
        UpdateHighlight();
    }

    /// <summary>
    /// Updates the highlight.
    /// </summary>
    public void UpdateHighlight()
    {
        if (this.AssociatedObject == null ||
            string.IsNullOrEmpty(this.AssociatedObject.Text) ||
            string.IsNullOrEmpty(this.SearchString))
        {
            ClearHighlight();
            return;
        }

        var txt = this.AssociatedObject.Text;
        var searchTxt = this.SearchString;
        var processedCharacters = 0;
        this.AssociatedObject.Inlines.Clear();

        int pos;

        while ((pos = txt.IndexOf(
            searchTxt,
            processedCharacters,
            this.IsCaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)) >= 0)
        {
            if (pos > processedCharacters)
            {
                var run = new Run
                {
                    Text =
                        txt.Substring(
                            processedCharacters, pos - processedCharacters)
                };

                this.AssociatedObject.Inlines.Add(run);
            }

            Run highlight;
            var highlightText = txt.Substring(pos, searchTxt.Length);

            if (this.HighlightTemplate == null)
            {
                highlight =
                    new Run
                    {
                        Text = highlightText,
                        Foreground = this.HighlightBrush
                    };
            }
            else
            {
                highlight = (Run)this.HighlightTemplate.LoadContent();
                highlight.Text = highlightText;
            }

            this.AssociatedObject.Inlines.Add(highlight);
            processedCharacters = pos + searchTxt.Length;
        }

        if (processedCharacters < txt.Length)
        {
            var run = new Run
            {
                Text =
                    txt.Substring(
                        processedCharacters, txt.Length - processedCharacters)
            };

            this.AssociatedObject.Inlines.Add(run);
        }
    }

    /// <summary>
    /// Clears the highlight.
    /// </summary>
    public void ClearHighlight()
    {
        if (this.AssociatedObject == null)
        {
            return;
        }

        var text = this.AssociatedObject.Text;
        this.AssociatedObject.Inlines.Clear();
        this.AssociatedObject.Inlines.Add(new Run{Text = text});
    }
}

public abstract class Behavior<T> : Behavior where T : DependencyObject
{
    #region Behavior() - CTOR
    /// <summary>
    /// Initializes a new instance of the <see cref="Behavior&lt;T&gt;"/> class.
    /// </summary>
    protected Behavior()
    {
        _associatedType = typeof(T);
    } 
    #endregion

    #region AssociatedObject
    /// <summary>
    /// Gets the object to which this <see cref="Behavior&lt;T&gt;" /> is attached.
    /// </summary>
    public new T AssociatedObject
    {
        get
        {
            return (T)_associatedObject;
        }
        internal set
        {
            _associatedObject = value;
        }
    } 
    #endregion
}

祝你好运!