Muy bien, he encontrado una solución que funciona para mi caso, pero puede no funcionar para todos los que quieran algo como esto. Es desordenado, pero cumple su función.
No voy a aceptar mi propia respuesta por unos días, solo en caso de que alguien más tenga una mejor manera de lograr esto.
Aquí vamos, en primer lugar, el XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="500"
Width="600">
<DockPanel LastChildFill="True">
<RichTextBox x:Name="rtb"
FontFamily="Courier New"
FontSize="14"
PreviewKeyDown="rtb_PreviewKeyDown">
<FlowDocument>
<Paragraph>
<InlineUIContainer Unloaded="InlineUIContainer_Unloaded">
<TextBlock FontFamily="Courier New" FontSize="14">This line of text is not editable.</TextBlock>
</InlineUIContainer>
<Run Foreground="Blue">But this is editable.</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</DockPanel>
</Window>
Y el código subyacente:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void InlineUIContainer_Unloaded(object sender, RoutedEventArgs e)
{
(sender as InlineUIContainer).Unloaded -= new RoutedEventHandler(InlineUIContainer_Unloaded);
TextBlock tb = new TextBlock();
tb.FontFamily = new FontFamily("Courier New");
tb.FontSize = 14;
tb.Text = "This line of text is not editable.";
TextPointer tp = rtb.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
InlineUIContainer iuic = new InlineUIContainer(tb, tp);
iuic.Unloaded += new RoutedEventHandler(InlineUIContainer_Unloaded);
}
private void rtb_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
var newPointer = rtb.Selection.Start.InsertLineBreak();
rtb.Selection.Select(newPointer, newPointer);
e.Handled = true;
}
}
}
}
Mi solución se basa en el hecho de que cuando un InlineUIContainer
se retira de la interfaz de usuario, es Unloaded()
método se llama. En ese punto, simplemente reinserto el InlineUIContainer
borrado en la posición actual de intercalación.
Como con cualquier hack, hay un montón de desventajas. Las desventajas que estoy encontrando son los siguientes:
- El texto que quiere ser de sólo lectura debe ser envuelto en una
InlineUIContainer
. Eso es un poco limitante para esta solución.
- Tengo que capturar la tecla 'Intro' e insertar saltos de línea manualmente, de lo contrario,
InlineUIContainer.Unloaded()
sigue disparando cada vez que se presiona la tecla Enter. No es divertido, pero funciona para mi caso.
No es una gran solución, pero creo que funcionará para mí. Como dije, no voy a marcar esto como una respuesta a mi propia pregunta todavía; con suerte, alguien más tendrá una mejor manera de hacerlo.
muy interesante que me ayudará a añadir "widgets" si ingresas al editor de texto. Estoy creando una ventana muy agradable como el editor Wiki. Entonces, para agregar imágenes, categorías y palabras clave, estoy usando pequeños objetos que decoran el objeto de texto enriquecido. Ojalá el editor fuera un poco más como el editor de estudio visual. De esta forma podría agregar "Adornos" pero ... ¡esto definitivamente me ayudó! Gracias. – JustinKaz
Me alegro de que pueda ayudar, pero tenga cuidado, recuerdo vagamente que es posible eliminar el texto de solo lectura con la tecla de retroceso.No estoy seguro después de todo este tiempo, pero lo probaría a fondo para garantizar que los widgets permanezcan como de solo lectura. –