Paging ListBox
Hello,
I have a ListBox with its ItemsTemplate set to a DataTemplate with known dimensions.
The DataTemplate presents my Product class, a list of which is the ListBox's ItemsSource.
I have modified the scrollbar template to override the commands for the up/down buttons
to ScrollBar.PageUpCommand and ScrollBar.PageDownCommand respectively, the aim
being to display items by page, fixed item count per page. I have taken care to size
the ListBox accordingly. Problem is, let's say I have 10 items per page and a total of
17 items. I want to show the first 10 in the first page and items 11-17 in the second
page with empty space at the bottom. The default behaviour of the ListBox is to display
the last 10 items, 7 to 17. I thought about padding the listbox with 3 invisible items
by using a trigger in the DataTemplate that gets activated by a property in my Product
business object (isPadding), and adding extra dummy items at the end of the list.
But it's not the Product's responsibility to make my ListBox show like it should, and it
causes side effects with other parts of my code adding these extra items at the end.
Is there a way I can resolve this in a similar or completely different fashion?
Thanks.
Respuestas
- Hi ykab,
It's better to page on the data source. A possible solution is use the CollectionViewSource object, we can use its Filter event to filter the data, and only display the page of data that needed. See my sample below for the details:
<Grid>
<ListBox Margin="20,19,12,60" Name="listBox1" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Height="23" HorizontalAlignment="Left" Margin="20,0,0,23" Name="button1" VerticalAlignment="Bottom" Width="75" Click="button1_Click">Button</Button>
<Button Height="23" HorizontalAlignment="Left" Margin="109,0,0,23" Name="button2" VerticalAlignment="Bottom" Width="75" Click="button2_Click">Button</Button>
<Button Height="23" Margin="206,0,0,23" Name="button3" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="75" Click="button3_Click">Button</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,191,23" Name="button4" VerticalAlignment="Bottom" Width="75" Click="button4_Click">Button</Button>
</Grid>
public partial class Paging : Window
{
public Paging()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Paging_Loaded);
}
void Paging_Loaded(object sender, RoutedEventArgs e)
{
int itemcount = 107;
for (int j = 0; j < itemcount; j++)
{
objs.Add(new MyOjbect() { ID = j, Name = "item" + j.ToString() });
}
// Calculate the total pages
totalPage = itemcount / itemPerPage;
if (itemcount % itemPerPage != 0)
totalPage += 1;
view.Source = objs;
// To display the last page by default.
currentPageIndex = totalPage - 1;
view.Filter += new FilterEventHandler(view_Filter);
listBox1.DataContext = view;
}
void view_Filter (object sender, FilterEventArgs e)
{
int index = objs.IndexOf((MyOjbect)e.Item);
if (index >= itemPerPage * currentPageIndex && index < itemPerPage * (currentPageIndex + 1))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
CollectionViewSource view = new CollectionViewSource();
ObservableCollection<MyOjbect> objs = new ObservableCollection<MyOjbect>();
int currentPageIndex = 0;
int itemPerPage = 20;
int totalPage = 0;
private void button1_Click(object sender, RoutedEventArgs e)
{
// Display next page
if (currentPageIndex < totalPage-1)
{
currentPageIndex++;
view.View.Refresh();
}
}
private void button2_Click(object sender, RoutedEventArgs e)
{
// Display previous page
if (currentPageIndex > 0)
{
currentPageIndex--;
view.View.Refresh();
}
}
private void button3_Click(object sender, RoutedEventArgs e)
{
// Display the first page
if (currentPageIndex != 0 )
{
currentPageIndex = 0;
view.View.Refresh();
}
}
private void button4_Click(object sender, RoutedEventArgs e)
{
// Display the last page
if (currentPageIndex != totalPage-1)
{
currentPageIndex = totalPage-1;
view.View.Refresh();
}
}
}
public class MyOjbect
{
public int ID { get; set; }
public string Name { get; set; }
}
If anything is unclear, please feel free to let me know.
Best Regards,
Zhi-Xin Ye
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework!- Marcado como respuestaZhi-Xin YeMSFT, Moderadorviernes, 06 de noviembre de 2009 5:46
Todas las respuestas
- Hi ykab,
It's better to page on the data source. A possible solution is use the CollectionViewSource object, we can use its Filter event to filter the data, and only display the page of data that needed. See my sample below for the details:
<Grid>
<ListBox Margin="20,19,12,60" Name="listBox1" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Height="23" HorizontalAlignment="Left" Margin="20,0,0,23" Name="button1" VerticalAlignment="Bottom" Width="75" Click="button1_Click">Button</Button>
<Button Height="23" HorizontalAlignment="Left" Margin="109,0,0,23" Name="button2" VerticalAlignment="Bottom" Width="75" Click="button2_Click">Button</Button>
<Button Height="23" Margin="206,0,0,23" Name="button3" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="75" Click="button3_Click">Button</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,191,23" Name="button4" VerticalAlignment="Bottom" Width="75" Click="button4_Click">Button</Button>
</Grid>
public partial class Paging : Window
{
public Paging()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Paging_Loaded);
}
void Paging_Loaded(object sender, RoutedEventArgs e)
{
int itemcount = 107;
for (int j = 0; j < itemcount; j++)
{
objs.Add(new MyOjbect() { ID = j, Name = "item" + j.ToString() });
}
// Calculate the total pages
totalPage = itemcount / itemPerPage;
if (itemcount % itemPerPage != 0)
totalPage += 1;
view.Source = objs;
// To display the last page by default.
currentPageIndex = totalPage - 1;
view.Filter += new FilterEventHandler(view_Filter);
listBox1.DataContext = view;
}
void view_Filter (object sender, FilterEventArgs e)
{
int index = objs.IndexOf((MyOjbect)e.Item);
if (index >= itemPerPage * currentPageIndex && index < itemPerPage * (currentPageIndex + 1))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
CollectionViewSource view = new CollectionViewSource();
ObservableCollection<MyOjbect> objs = new ObservableCollection<MyOjbect>();
int currentPageIndex = 0;
int itemPerPage = 20;
int totalPage = 0;
private void button1_Click(object sender, RoutedEventArgs e)
{
// Display next page
if (currentPageIndex < totalPage-1)
{
currentPageIndex++;
view.View.Refresh();
}
}
private void button2_Click(object sender, RoutedEventArgs e)
{
// Display previous page
if (currentPageIndex > 0)
{
currentPageIndex--;
view.View.Refresh();
}
}
private void button3_Click(object sender, RoutedEventArgs e)
{
// Display the first page
if (currentPageIndex != 0 )
{
currentPageIndex = 0;
view.View.Refresh();
}
}
private void button4_Click(object sender, RoutedEventArgs e)
{
// Display the last page
if (currentPageIndex != totalPage-1)
{
currentPageIndex = totalPage-1;
view.View.Refresh();
}
}
}
public class MyOjbect
{
public int ID { get; set; }
public string Name { get; set; }
}
If anything is unclear, please feel free to let me know.
Best Regards,
Zhi-Xin Ye
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework!- Marcado como respuestaZhi-Xin YeMSFT, Moderadorviernes, 06 de noviembre de 2009 5:46

