Efficient Paging In Silverlight 2.0
When it comes to ASP.NET, I am a huge fan of efficient code, and one of the most efficient ways to retrieve data from the server is to use paging. Paging has been around for a long time now, but it is not available out of the box in Silverlight 2.0. I thought this was a good time to demonstrate how to consume a WCF service in Silverlight, and to create efficient server side paging using LINQ.
Before we begin you need to have the Silverlight 2 Tools installed. You can go here to download it.
To begin with open Visual Studio 2008 and choose File > New > Project > Silverlight > Silverlight Application:
When you click OK a new dialog will appear. Accept the default settings. The rules of this application are to create a WCF service that returns records from the Windows event log. Some computers store event log entries that can contain hundreds of entries, so it is important to page through this data efficiently. Add a new class to the web application and name it EventEntry. Add the following code to the class:
C#
public class EventEntry
{
public string Message { get; set; }
}
public class TotalInfo
{
public List<EventEntry> Entries { get; set; }
public int Total { get; set; }
}
VB.NET
Public Class EventEntry
Private privateMessage As String
Public Property Message() As String
Get
Return privateMessage
End Get
Set(ByVal value As String)
privateMessage = value
End Set
End Property
End Class
Public Class TotalInfo
Private privateEntries As List(Of EventEntry)
Public Property Entries() As List(Of EventEntry)
Get
Return privateEntries
End Get
Set(ByVal value As List(Of EventEntry))
privateEntries = value
End Set
End Property
Private privateTotal As Integer
Public Property Total() As Integer
Get
Return privateTotal
End Get
Set(ByVal value As Integer)
privateTotal = value
End Set
End Property
End Class
The code above is self explanatory, but we will use it later. Next we need to create a Silverlight enabled WCF service. Right click the project and choose Add > New Item > Silverlight > Silverlight-enabled WCF service:
It is important to create a Silverlight enabled WCF service because the only binding supported by Silverlight 2.0 is basicHttpBinding. Once the WCF service is created, add the following code:
C#
[OperationContract]
public TotalInfo FetchEventLogEntries(int skip, int take)
{
TotalInfo info = new TotalInfo();
List<EventEntry> entries = new List<EventEntry>();
using (EventLog log = new EventLog("Application"))
{
info.Total = log.Entries.Count;
var query = log.Entries.Cast<EventLogEntry>()
.OrderByDescending(o => o.TimeWritten)
.Skip(skip).Take(take);
foreach (var item in query)
{
entries.Add(new EventEntry()
{
Message = item.Message
});
}
info.Entries = entries;
}
return info;
}
VB.NET
<OperationContract> _
Public Function FetchEventLogEntries(ByVal skip As Integer, ByVal take As Integer) As TotalInfo
Dim info As New TotalInfo()
Dim entries As New List(Of EventEntry)()
Using log As New EventLog("Application")
info.Total = log.Entries.Count
Dim query = log.Entries.Cast(Of EventLogEntry)().OrderByDescending(Function(o) o.TimeWritten).Skip(skip).Take(take)
For Each item In query
entries.Add(New EventEntry() With {.Message = item.Message})
Next item
info.Entries = entries
End Using
Return info
End Function
In the code above one method is decorated with the OperationContract attribute. This means that it is a public method that can be consumed by the Silverlight application. The method takes two arguments, skip and take. We use these two values in the LINQ query to page through the event log. The code uses the EventLog class which is in System.Diagnostics namespace. This gives you access to the Windows event log. I am using LINQ to query the event log and return an ordered list of event log entries and limit the amount of entries that are returned by the Skip and Take methods.
That’s the server code taken care of. Next is to build a Silverlight XAML file to display the data. Open the Silverlight project and view the Page.xaml file. Add the following XAML to the file:
<Grid x:Name="LayoutRoot" Background="Azure" HorizontalAlignment="Left" Width="Auto">
<StackPanel Width="800" Height="800">
<ListBox x:Name="lstEvent" Width="750" Height="500" Margin="10" BorderThickness="2" BorderBrush="Black">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="BurlyWood" BorderThickness="1" CornerRadius="4">
<TextBlock Text="{Binding Message}" x:Name="txtMessage" Width="710" TextWrapping="Wrap" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<ComboBox MaxDropDownHeight="150" UseLayoutRounding="True" x:Name="cboPaging" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Width="50" Height="25" SelectionChanged="cboPaging_SelectionChanged"></ComboBox>
</StackPanel>
</StackPanel>
</Grid>
In the above code, I am going to display the event log entry in a ListBoxItemTemplate. ItemTemplate’s are a great way to change the layout of controls. For this example I am inserting a TextBlock with a Border control surrounding it to give it a snappier appearance that just a line of text. The TextBlock text property is using Binding to display the Message property as the text. Paging through the event log entries will be managed by the ComboBox. The ComboBox will display a list of pages to page through. But before we can go any further, we need to add a Reference to the WCF service we created earlier. Right click on the Silverlight project and choose Add Service Reference. The service reference dialog will appear. Click the Discover button and Visual Studio will automatically locate WCF services in the solution:
Now that we have the reference, we can go ahead and add code to the Page.xaml file. Open the Page.xaml.cs file and add the following code:
C#
private int PageSize
{
get;
set;
}
public Page()
{
InitializeComponent();
PageSize = 10;
FetchData(0);
}
VB.NET
Private privatePageSize As Integer
Private Property PageSize() As Integer
Get
Return privatePageSize
End Get
Set(ByVal value As Integer)
privatePageSize = value
End Set
End Property
Public Sub New()
InitializeComponent()
PageSize = 10
FetchData(0)
End Sub
The PageSize property sets the maximum number of records to display at any time. The FetchData method requires one argument. This argument will be used in the LINQ query in the ECF service to determine where to start retrieving records. The PageSize value limits the number of rows returned. Add the following FetchData method:
C#
private void FetchData(int start)
{
ServiceReference1.ViewLogServiceClient client = new EventLogViewerApp.ServiceReference1.ViewLogServiceClient();
client.FetchEventLogEntriesCompleted += new EventHandler<FetchEventLogEntriesCompletedEventArgs>(client_FetchEventLogEntriesCompleted);
client.FetchEventLogEntriesAsync(start, PageSize);
}
VB.NET
Private Sub FetchData(ByVal start As Integer)
Dim client As ServiceReference1.ViewLogServiceClient = New EventLogViewerApp.ServiceReference1.ViewLogServiceClient()
AddHandler client.FetchEventLogEntriesCompleted, AddressOf client_FetchEventLogEntriesCompleted
client.FetchEventLogEntriesAsync(start, PageSize)
End Sub
Silverlight performs calls to WCF services asynchronously. In the code above, we are creating a new event handler for the FetchEventLogEntriesCompleted event. Add the following code for the event handler:
C#
void client_FetchEventLogEntriesCompleted(object sender, EventLogViewerApp.ServiceReference1.FetchEventLogEntriesCompletedEventArgs e)
{
lstEvent.ItemsSource = e.Result.Entries;
if (cboPaging.Items.Count == 0)
{
for (int i = 1; i < (e.Result.Total / PageSize) + 1; i++)
{
cboPaging.Items.Add(i);
}
}
}
VB.NET
Private Sub client_FetchEventLogEntriesCompleted(ByVal sender As Object, ByVal e As EventLogViewerApp.ServiceReference1.FetchEventLogEntriesCompletedEventArgs)
lstEvent.ItemsSource = e.Result.Entries
If cboPaging.Items.Count = 0 Then
For i As Integer = 1 To (e.Result.Total / PageSize)
cboPaging.Items.Add(i)
Next i
End If
End Sub
The e.Result will return the TotalInfo class which we defined as the return type. Binding the data to the ListBox is by settings the ItemsSource property. To add paging functionality, the TotalInfo class also returns a Total property, which is the count of all the records in the event log. I use this total and divide by the value in the PageSize property to determine the number of pages the user can choose from, but still the only data being displayed is the number of records in the PageSize property. Very efficient!
Finally you need to add the following code to handle the event when the user pages through the data:
C#
private void cboPaging_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int i = (int)cboPaging.SelectedItem;
int start = 0;
if (i > 1)
{
start = (i * PageSize) - PageSize;
}
FetchData(start);
}
VB.NET
Private Sub cboPaging_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
Dim i As Integer = CInt(Fix(cboPaging.SelectedItem))
Dim start As Integer = 0
If i > 1 Then
start = (i * PageSize) - PageSize
End If
FetchData(start)
End Sub
In the code above, first we page currently selected in the ComboBox. If it is equal to one, then the records selected from the WCF will start at zero and return ten records. If it is greater than one, it determines what the starting page is based on their selection. Run the project and you’ll be able to page through entries in your computers event log. Cool huh!
As I mentioned at the beginning of this article, I am a huge fan of efficient code, and LINQ’s built-in paging functionality is a great way to write efficient paging code with ease. The source code of this article can be downloaded from here.
Malcolm Sheridan is an independent contractor who has been working with Microsoft technologies since VB4. Malcolm has worked with .NET since its inception and thoroughly enjoys ASP.NET.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @
malcolmsheridan