【问题标题】:WPF Flowdocument "change case" featureWPF Flowdocument“更改大小写”功能
【发布时间】:2012-05-02 15:54:49
【问题描述】:

我正在为我的 RichTextBox 实现“更改大小写”功能,就像 word 使用 Shift+F3 一样。它所做的只是在小写->大写->标题大小写之间切换,一旦我可以访问我需要的字符串,这非常简单。

我的问题是,如何在流文档中更改(并首先找到它)字符串,而不会丢失可能包含在字符串中的任何嵌入元素(丢失格式不是问题)。 与 word 相同,我在 2 种情况下需要此功能:

1) 鼠标选择的文本。我尝试了简单的

this.Selection.Text = newText;

但这当然丢失了我的嵌入元素。

2) 插入符号位置之前的最后一个单词。任何非文本元素都是单词分隔符,但是一个单词可以是

"He<weird formatting begin>ll<weird formatting end>o".

【问题讨论】:

    标签: c# wpf flowdocument


    【解决方案1】:

    解决方案

    这种方式模仿 MS WORD Shift+F3 的行为。在极少数情况下发生的唯一问题是 carret 被移动到单词开头而不是保持其位置。我想在 EditingCommands.MoveLeftByWord.Execute(null, this); 之后短暂睡眠会解决这个问题,但这将是一个肮脏的黑客,我正在尝试找到一个更好的解决方案。

    private void ChangeCase()
        {
            try
            {
                TextPointer start;
                TextPointer end;
                FindSelectedRange(out start, out end);
                List<TextRange> textToChange = SplitToTextRanges(start, end);
                ChangeCaseToAllRanges(textToChange);
            }
            catch (Exception ex)
            {
                mLog.Error("Change case error", ex);
            }
    
    
        }
    
        private void FindSelectedRange(out TextPointer start, out TextPointer end)
        {
            if (!this.Selection.IsEmpty)
            {
                start = this.Selection.Start;
                end = this.Selection.End;
            }
            else
            {
                end = this.CaretPosition;
                EditingCommands.MoveLeftByWord.Execute(null, this);
                start = this.CaretPosition;
                this.CaretPosition = end;
    
            }
        }
    
        private static List<TextRange> SplitToTextRanges(TextPointer start, TextPointer end)
        {
            List<TextRange> textToChange = new List<TextRange>();
            var previousPointer = start;
            for (var pointer = start; pointer.CompareTo(end) <= 0; pointer = pointer.GetPositionAtOffset(1, LogicalDirection.Forward))
            {
                var contextAfter = pointer.GetPointerContext(LogicalDirection.Forward);
                var contextBefore = pointer.GetPointerContext(LogicalDirection.Backward);
                if (contextBefore != TextPointerContext.Text && contextAfter == TextPointerContext.Text)
                {
                    previousPointer = pointer;
                }
                if (contextBefore == TextPointerContext.Text &&  contextAfter != TextPointerContext.Text && previousPointer != pointer)
                {
                    textToChange.Add(new TextRange(previousPointer, pointer));
                    previousPointer = null;
                }
            }
            textToChange.Add(new TextRange(previousPointer ?? end, end));
            return textToChange;
        }
    
        private void ChangeCaseToAllRanges(List<TextRange> textToChange)
        {
            var textInfo = (mCasingCulture ?? CultureInfo.CurrentUICulture).TextInfo;
            var allText = String.Join(" ", textToChange.Select(x => x.Text).Where(x => !string.IsNullOrWhiteSpace(x)));
            Func<string, string> caseChanger = GetConvertorToNextState(textInfo, allText);
            foreach (var range in textToChange)
            {
                if (!range.IsEmpty && !string.IsNullOrWhiteSpace(range.Text))
                {
                    range.Text = caseChanger(range.Text);
                }
            }
        }
    
        private static Func<string, string> GetConvertorToNextState(TextInfo textInfo, string allText)
        {
            Func<string, string> caseChanger;
            if (textInfo.ToLower(allText) == allText)
            {
                caseChanger = (text) => textInfo.ToTitleCase(text);
            }
            else if (textInfo.ToTitleCase(textInfo.ToLower(allText)) == allText)
            {
                caseChanger = (text) => textInfo.ToUpper(text);
            }
            else
            {
                caseChanger = (text) => textInfo.ToLower(text);
            }
            return caseChanger;
        }
    

    【讨论】:

    • 大小写的变化方式存在一个小问题。如果您选择的文本同时是大写 标题(因为它只包含大写的单个字母单词),它什么也不做(例如“E E”)。一个简单的解决方法是将GetConvertorToNextState() 中的中间测试改为:else if (textInfo.ToTitleCase(textInfo.ToLower(allText)) == allText &amp;&amp; textInfo.ToUpper(allText) != allText)
    • “A1”也是这个问题的一个例子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-31
    • 1970-01-01
    • 2011-09-09
    • 2013-11-19
    • 2022-09-23
    • 1970-01-01
    • 2017-03-19
    相关资源
    最近更新 更多