Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Alright, I've come up with a solution that works for my case - but may not work for everyone who wants something like this. It's messy, but it does the job.</p> <p>I'm not going to accept my own answer for a few days, just in case someone else has a better way of accomplishing this.</p> <p>Here we go, first, the XAML:</p> <pre><code>&lt;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"&gt; &lt;DockPanel LastChildFill="True"&gt; &lt;RichTextBox x:Name="rtb" FontFamily="Courier New" FontSize="14" PreviewKeyDown="rtb_PreviewKeyDown"&gt; &lt;FlowDocument&gt; &lt;Paragraph&gt; &lt;InlineUIContainer Unloaded="InlineUIContainer_Unloaded"&gt; &lt;TextBlock FontFamily="Courier New" FontSize="14"&gt;This line of text is not editable.&lt;/TextBlock&gt; &lt;/InlineUIContainer&gt; &lt;Run Foreground="Blue"&gt;But this is editable.&lt;/Run&gt; &lt;/Paragraph&gt; &lt;/FlowDocument&gt; &lt;/RichTextBox&gt; &lt;/DockPanel&gt; &lt;/Window&gt; </code></pre> <p>And the code behind:</p> <pre><code>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; } } } } </code></pre> <p>My solution relies on the fact that when an <code>InlineUIContainer</code> is removed from the UI, it's <code>Unloaded()</code> method is called. At that point, I simply reinsert the deleted <code>InlineUIContainer</code> at the current caret position.</p> <p>As with any hack, there are a bunch of disadvantages. The disadvantages I'm finding are the following:</p> <ul> <li>The text I want to be read-only needs to be wrapped in a <code>InlineUIContainer</code>. That is a little limiting for this solution.</li> <li>I have to capture the 'Enter' key and insert line breaks manually, otherwise, <code>InlineUIContainer.Unloaded()</code> keeps firing everytime the Enter key is pressed. Not fun, but it works for my case.</li> </ul> <p>It's not a great solution, but I think it will work for me. Like I said, I'm not going to mark this as an answer to my own question yet - hopefully someone else will have a better way of doing this.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload