Search code examples
c#wpfxamlflowdocumentflowdocumentscrollviewer

FlowDocumentScrollViewer does not display text (WPF, XAML)


I have xaml with button and FlowDocumentScrollViewer:

<Button Content="My Button" Command="{Binding SomeButton}"/>
<FlowDocumentScrollViewer Document="{Binding FlowDocument}"/>

Now I want into VM add some logic:

private ICommand m_SomeButtonCommand ;
public ICommand SomeButton => m_SomeButtonCommand ?? (m_SomeButtonCommand = new RelayCommand(RunSM, true));

private void RunSM
{
  FlowDocument flowDocument = new FlowDocument();
  Paragraph paragraph = new Paragraph(new Run("some new Text"));

  paragraph.Background = Brushes.White;
  paragraph.Foreground = Brushes.Black;
  paragraph.FontSize = 14;

  m_flowDocumentScrollViewer = new FlowDocumentScrollViewer();
  m_flowDocumentScrollViewer.Document = flowDocument;
}

private FlowDocumentScrollViewer m_flowDocumentScrollViewer;

public FlowDocumentScrollViewer FlowDocumentScrollViewer
{
  get
  {
    return m_flowDocumentScrollViewer;
  }
  set
  {
    if (m_flowDocumentScrollViewer == value)
     return;

     m_flowDocumentScrollViewer = value;
    OnPropertyChanged();
  }
 }

 private FlowDocument m_flowDocument;
 public FlowDocument FlowDocument
    {
        get
        {
            return m_flowDocument;
        }

        set
        {
            if (m_flowDocument == value)
                return;

            m_flowDocument = value;
            OnPropertyChanged();
        }
    }

But nothing is display.


Solution

  • First of all, you should not declare property for FlowDocumentScrollViever inside your ViewModel - it is already backed with a field inside compiler generated CodeBehind partial class (your xaml.cs sibling).

    Second, instead of instantiating local variable in your RunSM() method, you could directly instantiate your FlowDocument property, like this:

    private void RunSM()
    {
        Paragraph paragraph = new Paragraph(new Run("some new Text"));
    
        paragraph.Background = Brushes.White;
        paragraph.Foreground = Brushes.Black;
        paragraph.FontSize = 14;
    
        ///note that im passing previously created paragraph, because the ONLY way to do it is through the constructor
        FlowDocument = new FlowDocument(paragraph);
    }
    

    Now, assuming your INotifyPropertyChanged is implemented properly (RaisePropertyChanged() call in FlowDocument setter), it should automatically notify UI with the changes, because FlowDocument property is already bound with your FlowDocumentScrollViewer:

    <FlowDocumentScrollViewer Document="{Binding FlowDocument}"/>
    

    Third, you should never set a value to your property's backing field directly when outside of it's (property) setter!

    So, instead of m_flowDocument = foo;, you should rather write FlowDocument = foo;.

    P.S. Correct me if im wrong, but the prefixed syntax (e.g. m_, s_) is no longer up to current C# naming conventions, so it's recommended not to use this, except in case when project convention enforces it.