void SetDecorations(swd.TextRange range, sw.TextDecorationCollection decorations, bool value) { using (Control.DeclareChangeBlock()) { // set the property to each element in the range so it keeps all other decorations foreach (var element in range.GetInlineElements()) { var existingDecorations = element.GetValue(swd.Inline.TextDecorationsProperty) as sw.TextDecorationCollection; // need to keep the range before changing otherwise the range changes var elementRange = new swd.TextRange(element.ElementStart, element.ElementEnd); sw.TextDecorationCollection newDecorations = null; // remove decorations from the element element.SetValue(swd.Inline.TextDecorationsProperty, null); if (existingDecorations != null && existingDecorations.Count > 0) { // merge desired decorations with existing decorations. if (value) { newDecorations = new sw.TextDecorationCollection(existingDecorations.Union(decorations)); } else { newDecorations = new sw.TextDecorationCollection(existingDecorations.Except(decorations)); } // split up existing decorations to the parts of the element that don't fall within the range existingDecorations = new sw.TextDecorationCollection(existingDecorations); // copy so we don't update existing elements if (elementRange.Start.CompareTo(range.Start) < 0) { new swd.TextRange(elementRange.Start, range.Start).ApplyPropertyValue(swd.Inline.TextDecorationsProperty, existingDecorations); } if (elementRange.End.CompareTo(range.End) > 0) { new swd.TextRange(range.End, elementRange.End).ApplyPropertyValue(swd.Inline.TextDecorationsProperty, existingDecorations); } } else { // no existing decorations, just set the new value newDecorations = value ? decorations : null; } if (newDecorations != null && newDecorations.Count > 0) { // apply new decorations to the desired range, which may be a combination of existing decorations swd.TextPointer start = elementRange.Start.CompareTo(range.Start) < 0 ? range.Start : elementRange.Start; swd.TextPointer end = elementRange.End.CompareTo(range.End) > 0 ? range.End : elementRange.End; new swd.TextRange(start, end).ApplyPropertyValue(swd.Inline.TextDecorationsProperty, newDecorations); } } } }