WPF Flowdocument和“变更案例"特征 [英] WPF Flowdocument "change case" feature
问题描述
我正在为RichTextBox实现更改大小写"功能,就像Shift + F3所具有的功能一样.它所做的就是在小写->大写->标题之间切换,一旦我访问了需要的字符串,这将非常简单.
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.
我的问题是,如何在流文档中更改(并首先找到它)字符串,而不会丢失任何可能包含在字符串中的嵌入元素(丢失格式不是问题).与word相同,在2种情况下我需要此功能:
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)鼠标选择的文本.我只是尝试
1) Mouse-selected text. I tried simply
this.Selection.Text = newText;
但是那当然失去了我的内在元素.
But that of course lost my embedded elements.
2)插入符号位置前的最后一个单词.任何非文本元素都是单词定界符,但是一个单词可以是
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".
推荐答案
解决方案
这样,它模仿了MS WORD Shift + F3行为.在极少数情况下会发生的唯一问题是将字头移到单词"begin"而不是保持其位置.我想在EditingCommands.MoveLeftByWord.Execute(null,this);之后会短暂入睡.可以解决此问题,但这将是一个肮脏的hack,我正在尝试找出更好的解决方案.
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和“变更案例"特征的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!