WPF的FlowDocument"变化情况"特征 [英] WPF Flowdocument "change case" feature

查看:148
本文介绍了WPF的FlowDocument"变化情况"特征的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现我的RichTextBox像字更改大小写的功能与Shift + F3。它所做的就是较低>大写>标题的情况下,一旦我获得我所需要的字符串,这是非常简单的之间的切换。



我的问题是,如何改变(并发现它摆在首位)的FlowDocument的字符串,而不会丢失任何嵌入元素(失去格式不是问题)可能包含字符串中。
一样的话,我需要2例此功能:



1)鼠标选中的文本。我想简单地



  this.Selection.Text = newText; 



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



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

 他<奇怪的格式开始> LL<奇怪的格式结束≠0。 


解决方案

SOLUTION



这方式,它模仿MS WORD Shift + F3行为。只有在极少数情况下会出现的问题是被移动到字开头,而不是保持其位置CARRET。我想,EditingCommands.MoveLeftByWord.Execute经过短暂的睡眠(null,则此);想解决这个问题,但是这将是一个肮脏的黑客,我试图找出一个更好的解决方案。

 私人无效ChangeCase( )
{

{
TextPointer启动;
TextPointer结束;
FindSelectedRange(出开始,OUT端);
名单,LT;&的TextRange GT; textToChange = SplitToTextRanges(开始,结束);
ChangeCaseToAllRanges(textToChange);
}
赶上(异常前)
{
mLog.Error(更改大小写错误,前);
}


}

私人无效FindSelectedRange(出TextPointer开始,出TextPointer完)
{
如果(! this.Selection.IsEmpty)
{
开始= this.Selection.Start;
端= this.Selection.End;
}
,否则
{
端= this.CaretPosition;
EditingCommands.MoveLeftByWord.Execute(null,则此);
开始= this.CaretPosition;
this.CaretPosition =结束;

}
}

私人静态列表<&的TextRange GT; SplitToTextRanges(TextPointer开始,TextPointer结束)
{
名单,LT;&的TextRange GT; textToChange =新的List<&的TextRange GT;();
VAR previousPointer =启动;
为(VAR指针=启动; pointer.CompareTo(完)< = 0;指针= pointer.GetPositionAtOffset(1 LogicalDirection.Forward))
{
VAR contextAfter = pointer.GetPointerContext (LogicalDirection.Forward);
VAR contextBefore = pointer.GetPointerContext(LogicalDirection.Backward);
如果(contextBefore = TextPointerContext.Text和放大器;!&安培; contextAfter == TextPointerContext.Text)
{
previousPointer =指针;
}
如果(contextBefore == TextPointerContext.Text&放大器;&安培;!contextAfter = TextPointerContext.Text&放大器;&安培;!previousPointer =指针)
{
textToChange.Add(新的TextRange(previousPointer,指针));
previousPointer = NULL;
}
}
textToChange.Add(新的TextRange(previousPointer ??结束,结束));
返回textToChange;
}

私人无效ChangeCaseToAllRanges(列表<&的TextRange GT; textToChange)
{
VAR TextInfo中=(mCasingCulture ?? CultureInfo.CurrentUICulture).TextInfo;
变种allText =的string.join(,textToChange.Select(X => x.Text)。凡(X =>!string.IsNullOrWhiteSpace(X)));
Func键<字符串,字符串> caseChanger = GetConvertorToNextState(TextInfo中,allText);
的foreach(在textToChange VAR范围)
{
如果(range.IsEmpty&安培;!&安培;!string.IsNullOrWhiteSpace(range.Text))
{
系列的.text = caseChanger(range.Text);
}
}
}

私有静态Func键<字符串,字符串> GetConvertorToNextState(TextInfo中TextInfo中,字符串allText)
{
Func键<字符串,字符串> caseChanger;
如果(textInfo.ToLower(allText)== allText)
{
caseChanger =(文本)=> textInfo.ToTitleCase(文本);
}
,否则如果(textInfo.ToTitleCase(textInfo.ToLower(allText))== allText)
{
caseChanger =(文本)=> textInfo.ToUpper(文本);
}
,否则
{
caseChanger =(文本)=> textInfo.ToLower(文本);
}
返回caseChanger;
}


I am implementing a "change case" functionality for my RichTextBox like word has with Shift+F3. All it does is switching between lower->upper->title case, which is very simple once I get access to the string I need.

My question is, how to change (and find it in the first place) a string in flowdocument without losing any embedded elements (losing formatting is not a problem) that may be contained within the string. Same as word, I need this functionality for 2 cases:

1) Mouse-selected text. I tried simply

this.Selection.Text = newText;

But that of course lost my embedded elements.

2) The last word before caret position. Any non-text element is a word delimiter, however one word can be

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

解决方案

SOLUTION

This way it mimics MS WORD Shift+F3 behaviour. Only problem that in very few cases occurs is the carret being moved to the word beginning instead of keeping its position. I suppose that a short sleep after EditingCommands.MoveLeftByWord.Execute(null, this); would fix this, but this would be a dirty hack and I am trying to find out a nicer solution.

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

这篇关于WPF的FlowDocument&QUOT;变化情况&QUOT;特征的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆