2009-07-05 17 views
11

Potrei averlo completamente immaginato, ma avrei giurato che c'era un modo per rendere i singoli elementi Run (o Parapgraph) in un oggetto Rich TextBox di sola lettura. Ho anche potuto giurare ho cercato un metodo per fare questo io stesso un paio di settimane fa, e sono rimasto soddisfatto con i risultati - Ricordo vagamente che sembrava qualcosa di simile:Elementi di sola lettura Esegui elementi in un RichTextBox WPF?

<RichTextBox x:Name="richTextBox" 
      AcceptsTab="True" 
      AcceptsReturn="True" 
      FontFamily="Courier New" 
      FontSize="14"> 
    <FlowDocument> 
     <Paragraph> 
      <Run IsReadOnly="True">I wish this was read-only!</Run> 
     </Paragraph> 
    </FlowDocument> 
</RichTextBox> 

Ora, un paio di settimane più tardi, vado per cercare di rendere gli elementi di esecuzione di sola lettura in un RichTextBox solo per trovarlo non sembra possibile.

This post on the MSDN forums sembra confermare.

L'ho immaginato completamente? O c'è un modo per fare ciò che voglio fare?

risposta

7

OK, ho trovato una soluzione che funziona per il mio caso, ma potrebbe non funzionare per tutti coloro che desiderano qualcosa di simile. È disordinato, ma fa il lavoro.

Non accetterò la mia risposta per alcuni giorni, nel caso in cui qualcun altro abbia un modo migliore per farlo.

Ci siamo, in primo luogo, il codice 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> 

E il codice dietro:

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; 
      } 
     } 
    } 
} 

La mia soluzione si basa sul fatto che quando un InlineUIContainer viene rimosso dall'interfaccia utente, è Unloaded() il metodo è chiamato. A quel punto, reinserisco semplicemente lo InlineUIContainer eliminato nella posizione attuale del cursore.

Come per qualsiasi altro trucco, ci sono molti svantaggi. Gli svantaggi che sto riscontrando sono i seguenti:

  • Il testo che voglio essere di sola lettura deve essere racchiuso in un InlineUIContainer. Questo è un po 'limitante per questa soluzione.
  • Devo acquisire il tasto "Invio" e inserire interruzioni di riga manualmente, altrimenti, InlineUIContainer.Unloaded() continua a sparare ogni volta che si preme il tasto Invio. Non è divertente, ma funziona per il mio caso.

Non è una soluzione eccezionale, ma penso che funzionerà per me. Come ho detto, non ho intenzione di contrassegnarlo come una risposta alla mia domanda ancora - spero che qualcun altro abbia un modo migliore per farlo.

+2

Molto interessante mi aiuterà aggiungo "widget" se vuoi nell'editor di testo. Sto facendo una finestra molto carina come l'editor di Wiki. Quindi per aggiungere immagini, categorie e parole chiave sto usando piccoli oggetti che decorano l'oggetto rich text. Vorrei che l'editor fosse un po 'più simile all'editor di Visual Studio. In questo modo ho potuto aggiungere "Adornamenti" ma ... questo mi ha sicuramente aiutato! Grazie. – JustinKaz

+0

Contento che potrebbe essere d'aiuto - sii avvertito, però - Ricordo vagamente che è possibile cancellare il testo di sola lettura con il tasto backspace.Non sono sicuro dopo tutto questo tempo, ma lo testerei accuratamente per assicurarmi che i widget rimangano di sola lettura. –

1

Ciò può essere ottenuto mediante la gestione di due eventi: 1) OnMouseDown 2) OnPreviewKeyDown

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows.Controls; 
using System.Windows; 
using System.Windows.Input; 

namespace WpfApplication2 
{ 
public class MultiPartTextBox : TextBox 
{ 
    private string _prefix; 
    private string _content; 

    public string Prefix 
    { 
     get { return _prefix; } 
     set { _prefix = value; 
     Text = _prefix; 
     } 
    } 

    public string Content 
    { 
     get { return _content; } 
     set { 
      _content = value; 
      Text = _prefix + _content; 
     } 
    } 

    public MultiPartTextBox() { _prefix = string.Empty; } 

    protected override void OnMouseDown(MouseButtonEventArgs e) 
    { 

     base.OnMouseDown(e); 
     this.SelectionStart = _prefix.Length; 
     this.SelectionLength = 0; 
    } 

    //tab In 
    protected override void OnGotFocus(RoutedEventArgs e) 
    { 
     this.SelectionStart = _prefix.Length; 
     this.SelectionLength = 0; 
     base.OnGotFocus(e); 
    } 

    protected override void OnPreviewKeyDown(KeyEventArgs e) 
    { 
     if (e.Key == Key.Back 
      || e.Key == Key.Delete 
      || e.Key==Key.Left) 
     { 
      if (CaretIndex <= _prefix.Length) 
      { 
       e.Handled = true; 
       return; 
      } 
     } 
     base.OnPreviewKeyDown(e); 
    } 
    } 
    } 

in XAML dobbiamo gestire la cosa in questo modo:

xmlns:uc="clr-namespace:WpfApplication2" 

     <uc:MultiPartTextBox Height="30" HorizontalAlignment="Left" 
      Margin="80,94,0,0" x:Name="multiPartTxt1" VerticalAlignment="Top" 
      Width="224" Prefix="NON-EDITABLE" CaretIndex="4" >    
     </uc:MultiPartTextBox> 
+0

Hai dimenticato i tocchi delle dita. – McKay

Problemi correlati