Keep selection visual in RichEditBox on unfocus?

我是研究僧i 提交于 2019-12-23 01:59:12

问题


Does someone know a way to keep the visual selection state of a selected text in a RichEditBox? I want to add some basic text editing to my Windows 8.1 App but every time I select a text and click on another UI Element within the app, the RichEditBox hides the selection.

I already tried to register the unfocus event an set the selection range again but unfortunately this has no effect.

I also tried to draw my own rect over the Text using

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

This works as long as only some text within a single line is selected. If the selection is multilined I only get the top-left of and the bottom-right position of the selected Text. It seems like these are the mouse Positions where the selection where started and where it ended.

Are there any other ways keep to the selected text visibible when the RichEditBox is unfocused.


回答1:


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;
    }
}



回答2:


In the WinRT Toolkit, there's a HighlightBehavior that doesn't directly solve your problem, but might offer you a solution that is acceptable.

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
}

Best of luck!



来源:https://stackoverflow.com/questions/25122775/keep-selection-visual-in-richeditbox-on-unfocus

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!