// See msdn's ITextStoreACP documentation for a full description. public void InsertTextAtSelection(UnsafeNativeMethods.InsertAtSelectionFlags flags, char[] text, int cch, out int startIndex, out int endIndex, out UnsafeNativeMethods.TS_TEXTCHANGE change) { ITextPointer startNavigator; ITextPointer endNavigator; int selectionStartIndex; int selectionEndIndex; startIndex = -1; endIndex = -1; change.start = 0; change.oldEnd = 0; change.newEnd = 0; if (IsReadOnly) { throw new COMException(SR.Get(SRID.TextStore_TS_E_READONLY), UnsafeNativeMethods.TS_E_READONLY); } // // ITextRange range = new TextRange(this.TextSelection.AnchorPosition, this.TextSelection.MovingPosition); range.ApplyTypingHeuristics(false /* overType */); ITextPointer start; ITextPointer end; GetAdjustedSelection(range.Start, range.End, out start, out end); // Someone might change the default selection gravity, so use our // own TextPositions to track the insert. startNavigator = start.CreatePointer(); startNavigator.SetLogicalDirection(LogicalDirection.Backward); endNavigator = end.CreatePointer(); endNavigator.SetLogicalDirection(LogicalDirection.Forward); selectionStartIndex = startNavigator.CharOffset; selectionEndIndex = endNavigator.CharOffset; // Do the insert. if ((flags & UnsafeNativeMethods.InsertAtSelectionFlags.TS_IAS_QUERYONLY) == 0) { // Opene a composition undo unit for the composition undo. CompositionParentUndoUnit unit = OpenCompositionUndoUnit(); UndoCloseAction undoCloseAction = UndoCloseAction.Rollback; try { VerifyTextStoreConsistency(); change.oldEnd = selectionEndIndex; string filteredText = FilterCompositionString(new string(text), range.Start.GetOffsetToPosition(range.End)); // does NOT filter MaxLength. if (filteredText == null) { throw new COMException(SR.Get(SRID.TextStore_CompositionRejected), NativeMethods.E_FAIL); } // We still need to call ApplyTypingHeuristics, even though // we already did the work above, because it might need // to spring load formatting. this.TextSelection.ApplyTypingHeuristics(false /* overType */); //Invariant.Assert(this.TextSelection.Start.CompareTo(range.Start) == 0 && this.TextSelection.End.CompareTo(range.End) == 0); // We cannot make this Assertion because TextRange will normalize // differently around Floater/Inline edges. This is probably // not desired behavior. To repro, // // <StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > // <RichTextBox FontSize="24" Height="150"> // <FlowDocument> // <Paragraph> // <Run>para</Run> // <Floater HorizontalAlignment="Right" Width="100" Background="#FFFF0000"> // <Paragraph><Run>Floater</Run></Paragraph> // </Floater> // <Run> </Run> // </Paragraph> // </FlowDocument> // </RichTextBox> // </StackPanel> // // 1. Put the caret before the Floater. // 2. Shift-right to select the entire Floater. // 3. Activate the chinese pinyin IME, and press 'a'. // Avoid calling Select when the selection doesn't need a // final reposition to preserve any spring loaded formatting // from ApplyTypingHeuristics. if (start.CompareTo(this.TextSelection.Start) != 0 || end.CompareTo(this.TextSelection.End) != 0) { this.TextSelection.Select(start, end); } if (!_isComposing && _previousCompositionStartOffset == -1) { // IMEs have the option (TF_IAS_NO_DEFAULT_COMPOSITION) // of inserting text (via this method only) without first // starting a composition. If that happens, we need // to remember where the composition started, from the // point of view of the application listening to events // we will raise in the future. _previousCompositionStartOffset = this.TextSelection.Start.Offset; _previousCompositionEndOffset = this.TextSelection.End.Offset; } this.TextEditor.SetSelectedText(filteredText, InputLanguageManager.Current.CurrentInputLanguage); change.start = startNavigator.CharOffset; change.newEnd = endNavigator.CharOffset; ValidateChange(change); VerifyTextStoreConsistency(); undoCloseAction = UndoCloseAction.Commit; } finally { // Close a composition undo unit with commit to add the composition undo unit into the undo stack. CloseTextParentUndoUnit(unit, undoCloseAction); } } // Report the location of the new text. if ((flags & UnsafeNativeMethods.InsertAtSelectionFlags.TS_IAS_NOQUERY) == 0) { startIndex = selectionStartIndex; endIndex = endNavigator.CharOffset; } }