« Universal web application pattern vs. Experience first pattern | Main | Photoscroll -- the worst named WPF demo application with source code! »

Binding a table in a FlowDocument

Inspired by a post from Paul here providing a method to bind data to a FlowDocument Run object, I extended the idea to bind to a dynamic Table.  I prefer the attached property syntax in Paul's approach to a "BindableRun" object that Filipe used here. I didn't change the name from Paul's code (the name was fine for my purposes).

 

  public static class BindableExtender
  {
    public static Table GetBindableTable(DependencyObject obj)
    {
      return (Table)obj.GetValue(BindableTableProperty);
    }
    public static void SetBindableTable(DependencyObject obj, Table tbl)
    {
      obj.SetValue(BindableTableProperty, tbl);
    }
 
    public static string GetBindableText(DependencyObject obj)
    {
      return (string)obj.GetValue(BindableTextProperty);
    }
 
    public static void SetBindableText(DependencyObject obj,
        string value)
    {
      obj.SetValue(BindableTextProperty, value);
    }
 
    public static readonly DependencyProperty BindableTextProperty =
        DependencyProperty.RegisterAttached("BindableText" ,
            typeof(string) ,
                typeof(BindableExtender),
                new UIPropertyMetadata(null,
                BindableProperty_PropertyChanged));
 
    public static readonly DependencyProperty BindableTableProperty =
        DependencyProperty.RegisterAttached("BindableTable",
            typeof(Table),
                typeof(BindableExtender),
                new UIPropertyMetadata(null,
                BindableProperty_PropertyChanged));
 
    private static void BindableProperty_PropertyChanged(
        DependencyObject dependencyObject,
        DependencyPropertyChangedEventArgs e)
    {
      if (dependencyObject is Run)
      {
        ((Run)dependencyObject).Text = (string)e.NewValue;
      }
      if (dependencyObject is FlowDocument)
      {
        ((FlowDocument)dependencyObject).Blocks.Clear();
        if (e.NewValue != null)
        {
          ((FlowDocument)dependencyObject).Blocks.Add((Block)e.NewValue);
        }
      }
 
    }
  }

 

I added all of the code that handles Tables. Not too hard to find. The important stuff regarding binding happens in the PropertyChanged event. If the object passed is a FlowDocument, the code clears the current blocks that might be in the existing FlowDocument and then adds the Table.

How did I build the table? Using code like this to build the table:

 

private static Table BuildTable()
{
  Table tbl = new Table();
  TableRowGroup rowGrp = new TableRowGroup();
 
  tbl.RowGroups.Add(rowGrp);
 
  TableRow row = new TableRow();
  rowGrp.Rows.Add(row);
  // you can style a row ...
  // row.Style = Application.Current.TryFindResource("HeaderRowStyle") as Style;
  row.Cells.Add(new TableCell(new Paragraph(new Run("DataLabel:"))));
 
  Paragraph pg = new Paragraph();
  // or you can style a Paragraph
  // I couldn't get pg.SetResourceReference(Paragraph.StyleProperty, "DataStyle") to work
  // it seems to never locate the Style resource properly ... the other approach below works
  // however
  // pg.Style = Application.Current.TryFindResource("DataStyle") as Style;
  pg.Inlines.Add(new Run("Some data"));
  row.Cells.Add(pg);
 
  return tbl;
}

 

I added a property to the class bound by the UI:

 

    public Table Metadata
    {
      get { return BuildTable(); }
    }

 

Then, in the XAML, I bound to the property:

 

<FlowDocument local:BindableExtender.BindableTable="{Binding Path=Metadata}">
  <Paragraph/>
</FlowDocument>

 

The important thing to note here is the use of the attached property: local:BindableExtender.BindableTable.

The local namespace refers back to the host namespace (and since it's in the same assembly, the syntax just includes the namespace):

 

xmlns:local="clr-namespace:PhotoScroll"

 

 

 

Technorati tags: ,

Comments

Good post! I have some drafts sitting in my blog for a whole suite of elements/properties that add binding within FlowDocument.

I'll publish them soon, promise :)

I look forward to seeing them!

Help support my web site by searching and buying through Amazon.com (in assocation with Amazon.com).