question

ChristopherBauer-8283 avatar image
1 Vote"
ChristopherBauer-8283 asked ChristopherBauer-8283 commented

What is the correct MVVM way to put custom data into RichTextBox

I'm running into massive headaches while trying to create an editor using a RichTextBox.

I have been searching for a week, and all of the answers I have found describe making a custom control RichTextBox, and binding to a "string DocumentXaml" property, or using Xceed's Toolkit that has that ability to bind built in, and then using some text converter to convert the data to a string representation in Xaml and feeding that to the RichTextBox.

The problem with just translating my data into a string is then the RichTextBox loses all context of what the data is. I don't need to just display the data, I need to enforce certain restrictions on the way the text is edited.

Here's a simplified version of my data structures:

 class Script {
     public ObservableCollection<Scene> Scenes;
 };
    
 class Scene {
     public ObservableCollection<Note> SceneNotes;
     public ObservableCollection<Line> Lines;
 };
    
 class Line {
     public ObservableCollection<Note> Notes;
     public string Actor;
     public string Text;
 };
    
 class Note {
     public NoteType Type;
     public string Text;
 };


In my editor, a line of text is not just in 12 point font and center justified. That block of text is an Actor name, so there are restrictions on what you can do with it. I can't allow the user to change the font or the color, or make it left justified. That text represents an Actor, so it must ALWAYS be center justified in 12 point font. And so on. I need very strict control over what the user can and can't do inside the RichTextBox.

How do I do this? Is this just impossible in MVVM? My View class has the RichTextBox, but it has no idea about the Model. The ViewModel has the data, but I can not find a way to get the ViewModel access to the FlowDocument that lives inside the RichTextBox. What is the proper way to set up my classes so that I have some piece of code that can tightly control what goes into the RichTextBox? Or am I just approaching this problem completely incorrectly?

dotnet-csharpwindows-wpf
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

DaisyTian-1203 avatar image
0 Votes"
DaisyTian-1203 answered ChristopherBauer-8283 commented

How about setting the Foreground and FontSize for the FlowDocument in the converter? I make a demo for it.

 <Window.Resources>
         <local:FlowDocumentToXamlConverter x:Key="flowDocumentConverter"/>
     </Window.Resources>
     <Window.DataContext>
         <local:MainWindowViewModel></local:MainWindowViewModel>
     </Window.DataContext>
 <local:MyRichTextBox Grid.Row="0" x:Name="EditBox" Document="{Binding Path=DocumentXaml, Converter={StaticResource flowDocumentConverter}, Mode=TwoWay}"/>

The code for converter is:

 [ValueConversion(typeof(string), typeof(FlowDocument))]
     public class FlowDocumentToXamlConverter : IValueConverter
     {
         public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
         {
             var flowDocument = new FlowDocument();
             if (value != null)
             {
                 var xamlText = (string)value;
                 flowDocument = (FlowDocument)XamlReader.Parse(xamlText);
             }
             flowDocument.FontSize = 30;
             flowDocument.FontStyle = FontStyles.Italic;
             flowDocument.Foreground = Brushes.Red;
             flowDocument.TextAlignment = TextAlignment.Center;
                
             return flowDocument;
         }
         public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
         {
             if (value == null) return string.Empty;
             var flowDocument = (FlowDocument)value;
             flowDocument.FontSize = 30;
             flowDocument.FontStyle = FontStyles.Italic;
             flowDocument.Foreground = Brushes.Red;
             flowDocument.TextAlignment = TextAlignment.Center;
             return XamlWriter.Save(flowDocument);
         }
     }

If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

The FlowDocumentToXamlConverter is passed the entire Xaml string for the entire document at once, isn't it? This doesn't seem to work for me because not all of the text is formatted the same. Actor names are different from text, and different Note types will be different colors. One Paragraph will be red and another blue, and a third green. and I don't see how to make the FlowDocumentToXamlConverter know what paragraphs need to have what styles applied to them.

This also doesn't seem to help me enforce the editing restrictions?

The way this worked pre-MVVM, was code behind for PreviewKeyDown() that allowed it to do logic like: "The user pressed the Enter key while in a Block that signifies an Actor name - Create a new Block() for the Text that comes after, assign this font, and this formatting, insert that into the FlowDocument, and place the caret in that Block"

Where does that type of logic live in MVVM?

0 Votes 0 ·