2012-04-30 6 views
0

Shift + F3을 사용하여 단어처럼 RichTextBox에 "변경 사례"기능을 구현합니다. 모든 것은 lower-> upper-> title 사이를 전환하는 것으로, 필요한 문자열에 액세스하면 매우 간단합니다.WPF Flowdocument "대소 문자 바꾸기"기능

제 질문은, 문자열에 포함될 수있는 임베디드 요소를 잃지 않고 (서식을 잃지 않고) flowdocument에서 문자열을 변경 (처음부터 찾으십시오)하는 방법입니다. 단어와 동일하므로 2 가지 경우에이 기능이 필요합니다.

1) 마우스로 선택한 텍스트. 간단히 대답했습니다.

this.Selection.Text = newText; 

하지만 내 임베디드 요소를 잃어 버렸습니다.

2) 캐럿 위치 이전의 마지막 단어. 모든 텍스트가 아닌 요소는 단 하나 개의 단어가

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

답변

0

솔루션

은 MS WORD 시프트 + F3 동작을 모방이 방법이 될 수있다, 단어 구분 기호입니다. 극소수의 경우에만 발생하는 문제는 카레트가 그 위치를 유지하는 대신 단어의 처음으로 이동한다는 것입니다. 나는 짧은 잠을 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; 
    }