1

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

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

我还尝试使用在文本上绘制自己的矩形

richEdit.Document.Selection.GetRect(PointOptions.ClientCoordinates,out selectionRect, out hitCount );

只要仅选择了单行中的某些文本,此方法就可以工作。如果选择是多行的,我只会得到所选文本的左上角和右下角位置。似乎这些是选择开始和结束的鼠标位置。

当 RichEditBox 未聚焦时,是否有任何其他方法可以使所选文本保持可见。

4

2 回答 2

2

I found another workaround. Just set the selection Background when the RichEditBox is unfocused. But Jerry's Post gave me the Inspiration to this solution. Seems like this way was to simple to find it a first place:

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;
    }
}
于 2014-08-06T10:36:14.847 回答
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
}

祝你好运!

于 2014-08-05T01:41:02.873 回答