views:

26

answers:

1

I'm trying to implement my custom paginator to print listbox contents. I use a custom item template which can have different heights.

I'm able to add the items on the pages but sometimes the item has to be splitted into two parts. Does anyone know a good splitting algorithm to avoid that text inside this item is splitted horizontally?

It is quite difficult to find solutions for this kind of pagination. All of the pagination examples i've found have fixed item heights. Using a FlowDocument is not an option because it has performance issues while using many items.

Thanks for advises.

A: 

I solved this by creating an attached dependency property in a static class, PaginationBlocking:

public static class PaginationBlocking
{
    public static IList<UIElement> GetBlockList(UIElement element)
    {
        return (IList<UIElement>)element.GetValue(BlockListProperty);
    }

    public static void SetBlockList(UIElement element, IList<UIElement> value)
    {
        element.SetValue(BlockListProperty, value);
    }

    public static readonly DependencyProperty BlockListProperty =
        DependencyProperty.RegisterAttached("BlockList", typeof(IList<UIElement>), 
            typeof(PaginationBlocking), new UIPropertyMetadata(null, OnBlockListPropertyAttached));

    static void OnBlockListPropertyAttached(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as UIElement;
        if(element.is_null() || (bool)element.GetValue(IsBlockListOwnerProperty)) return;

        var list = e.NewValue as IList<UIElement>;
        if(list.is_null()) return;

        if(!list.Contains(element)) list.Add(element);
    }
}

I attach the property to any element that I don't want to break across pages:

<local:MyUserControl Height="20" UI:PaginationBlocking.BlockList="{Binding blockList}" />
<local:MyUserControl Height="30" UI:PaginationBlocking.BlockList="{Binding blockList}" />

Obviously you have to have a List<UIElement> to which you can bind. Binding a UIElement adds it to the bound list.

I paginate by creating a VisualBrush and painting the background of a Canvas with it. When I am paginating, I enumerate all of the elements in the list to get their y-offset relative to the upper-left corner. I iterate until I reach an item whose y-offset exceeds the available space for the page. I basically subtract one item and make that the last one for the page.

I don't really have code to show because my implementation is littered with other things (like scaling and capturing column headers to re-render at the top of the next page), but that is the gist of it.

Jay