Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Load rtf in bindable RichTexBox mvvm wpf

I'm new to mvvm and I would like to load an rtf file in a RichTextBox using mvvm, but the text doesn't seem to display in my richtextbox. Looks like RichTextBox is pretty complex to deal with when trying to place the commands in the ViewModel. I'm not sure where I go wrong.

ViewModel

 FlowDocument _script;
 public FlowDocument Script 
    {
        get { return _script; }
        set { _script = value; RaisePropertyChanged("Script"); }
    }
.
.
.
 private void LoadScript()
    {
        openFile.InitialDirectory = "C:\\";

        if (openFile.ShowDialog() == true)
        {
            string originalfilename = System.IO.Path.GetFullPath(openFile.FileName);

            if (openFile.CheckFileExists)
            {
                Script = new FlowDocument();
                TextRange range = new TextRange(Script.ContentStart, Script.ContentEnd);
                FileStream fStream = new FileStream(originalfilename, System.IO.FileMode.OpenOrCreate);
                range.Load(fStream, DataFormats.Rtf);
                fStream.Close();
            }  
         }
    }

the View

DataContext="{Binding ScriptBreakdownViewModel, Source={StaticResource Locator}}">

<Grid>
    <RichTextBox
        Local:RichTextBoxHelper.DocumentRtf="{Binding Script}"
        x:Name="rtfMain"
        HorizontalAlignment="Left"
        Width="673"
        VerticalScrollBarVisibility="Visible"
        Margin="0,59,0,10.4"
        />

the RichTextBoxHelper

public class RichTextBoxHelper : DependencyObject
{
    public static string GetDocumentRtf(DependencyObject obj)
    {
        return (string)obj.GetValue(DocumentRtfProperty);
    }
    public static void SetDocumentRtf(DependencyObject obj, string value)
    {
        obj.SetValue(DocumentRtfProperty, value);
    }
    public static readonly DependencyProperty DocumentRtfProperty =
      DependencyProperty.RegisterAttached(
        "DocumentRtf",
        typeof(string),
        typeof(RichTextBoxHelper),
        new FrameworkPropertyMetadata
        {
            BindsTwoWayByDefault = true,
            PropertyChangedCallback = (obj, e) =>
            {
                var richTextBox = (RichTextBox)obj;

               //  Parse the XAML to a document (or use XamlReader.Parse())
                var Rtf = GetDocumentRtf(richTextBox);
                var doc = new FlowDocument();
                var range = new TextRange(doc.ContentStart, doc.ContentEnd);

                range.Load(new MemoryStream(Encoding.UTF8.GetBytes(Rtf)),
                  DataFormats.Rtf);

               //  Set the document
                richTextBox.Document = doc;

               //  When the document changes update the source
                range.Changed += (obj2, e2) =>
                {
                    if (richTextBox.Document == doc)
                    {
                        MemoryStream buffer = new MemoryStream();
                        range.Save(buffer, DataFormats.Rtf);
                        SetDocumentRtf(richTextBox,
                          Encoding.UTF8.GetString(buffer.ToArray()));
                    }
                };
            }
        });
}

and the model

  FlowDocument _script;
  public FlowDocument Script   // the Name property
    {
        get { return _script; }
        set { _script = value; NotifyPropertyChanged("Script"); }
    }
like image 672
Phil Avatar asked Sep 28 '22 15:09

Phil


1 Answers

I tried to fill in the gaps in your sample code above, but your dependency property is never triggered.

Instead, I got the RichTextBox to populate by changing the XAML slightly:

    <Button Height="30" Width="70" VerticalAlignment="Top" Command="{Binding OpenFileCommand}" CommandParameter="{Binding ElementName=myRichTextBox}">Load</Button>
    <RichTextBox Name="myRichTextBox"
        HorizontalAlignment="Left"
        Width="673"
        VerticalScrollBarVisibility="Visible"
        Margin="0,59,0,10.4"></RichTextBox>

There is a button bound to the OpenFileCommand, which is a property on the ViewModel. It passes the RichTextBox as a parameter to the Command itself. I've moved the LoadScript() method from the ViewModel to the Command.

public class OpenFileCommand : ICommand
{
    private OpenFileDialog openFile = new OpenFileDialog();

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        var rtf = parameter as RichTextBox;
        rtf.Document = LoadScript();
    }

    public event EventHandler CanExecuteChanged;

    private FlowDocument LoadScript()
    {
        openFile.InitialDirectory = "C:\\";

        if (openFile.ShowDialog() == true)
        {
            string originalfilename = System.IO.Path.GetFullPath(openFile.FileName);

            if (openFile.CheckFileExists)
            {
                var script = new FlowDocument();
                TextRange range = new TextRange(script.ContentStart, script.ContentEnd);
                FileStream fStream = new FileStream(originalfilename, System.IO.FileMode.OpenOrCreate);
                range.Load(fStream, DataFormats.Rtf);
                fStream.Close();
                return script;
            }
        }

        return null;
    }
}
like image 50
pete the pagan-gerbil Avatar answered Nov 15 '22 05:11

pete the pagan-gerbil