The IPostBackDataHandler contains two main methods:
IPostBackDataHandler.RaisePostDataChangedEvent
IPostBackDataHandler.LoadPostData
How are those two methods used when they are being
implemented in a control?
Although this question is not the topic of this article, we
are going to give a brief overview of what happens when the Page builds its
control tree and how each control fires specific events based on the interfaces
it implements.
When a post back happens, the Page recreates its tree of
controls. It starts from the main control, which is the Page itself, then for
the children controls and the same continues for the sub children controls.
For each control it is being checked whether it implements
some interfaces or not. Among those interfaces is the IPostBackDataHandler. If
this interface is implemented, this means that the control has implemented the
above mentioned two methods.
Those methods are usually implemented to handle any posted
back data. By default, in ASP.NET the ListBox implements the above two
methods.
The LostPostData is being implemented to detect the selected
index or indices in case the ListBox is configured to be in the Multiple
Selection mode.
What we will do is implement the LoadPostData method. First
of all, we well keep the default behavior of this method, where we detect the
selected index or indices and we will get the data stored in both Hidden Fields
mentioned above.
The data stored in those two Hidden Fields will be used to remove
items from the ListBox and, in this case, the _REMOVED Hidden Field is queried
to get all the item indices to remove from the ListBox. The _ADDED Hidden
Field is queried to get all the items that will be added to the Items
collection of the ListBox.
The code below shows the implementation of the LoadPostData.
Listing 4
bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection
postCollection)
{
// Handle the SelectedIndex or Indicies
string[]postedItems = postCollection.GetValues(postDataKey);
bool returnValue = false;
// If no selection is done on the client side
if (postedItems == null)
{
if (this.SelectedIndex != - 1)
{
returnValue = true;
}
// No further processing for the Selected Index/Indicies
goto HandleClientChanges;
}
// If selection is in single mode
if (this.SelectionMode == ListSelectionMode.Single)
{
if (postedItems != null)
{
// Process first item, since we have a single selection
// ListItem item = this.FindByValueInternal(postedItems[0]);
int index = this.FindByValueInternal(postedItems[0]);
//Items.IndexOf(item);
if (this.SelectedIndex != index)
{
// Change occurred
this.SelectedIndex = index;
returnValue = true;
}
}
}
// Else, the selection mode is multiple
int numberOfItemsSelected = postedItems.Length;
// Old selected items
ArrayList oldSelectedItems = this.SelectedIndicesInternal;
// An empty arraylist of the currently selected items on the clisnde side
ArrayList currentlySelectedItems = new ArrayList(numberOfItemsSelected);
// Fill in all the indicies of the posted selected items
for (int i = 0; i < numberOfItemsSelected; i++)
{
currentlySelectedItems.Add(this.FindByValueInternal(postedItems[i]));
}
// Get the number of currently selected indicies
int numberOfSelectedItems = 0;
if (oldSelectedItems != null)
{
numberOfSelectedItems = oldSelectedItems.Count;
}
// Check if both numbers are equal
if (numberOfItemsSelected == numberOfSelectedItems)
{
for (int j = 0; j < numberOfItemsSelected; j++)
{
int oldSelect = Convert.ToInt32(currentlySelectedItems[j]);
int currentSelect = Convert.ToInt32(oldSelectedItems[j]);
if (oldSelect != currentSelect)
{
// Explicitly mark the item selected
this.Items[j].Selected = true;
returnValue = true;
}
}
}
else
{
// The number of selected items has changed
returnValue = true;
}
// Reset all selections to the newly selected items
if (returnValue)
{
this.SelectInternal(currentlySelectedItems);
}
// Section to handle ADDED and REMOVED Items.
HandleClientChanges:
// Remove the items from the Items collection
// that were marke for deletion on client side// Handle items added on Client Side
string itemsRemoved = postCollection[this.HFItemsRemoved];
string[]itemsRemovedCol = itemsRemoved.Split(',');
if (itemsRemovedCol != null)
{
if ((itemsRemovedCol.Length > 0) && (itemsRemovedCol[0] != ""))
{
for (int i = 0; i < itemsRemovedCol.Length; i++)
{
ListItem itemToRemove = this.Items.FindByValue(itemsRemovedCol[i]);
// Remove from the Items Collection
Items.Remove(itemToRemove);
}
returnValue = true;
}
}
// Handle items added on Client Side
string itemsAdded = postCollection[this.HFItemsAdded];
string[]itemsCol = itemsAdded.Split(',');
if (itemsCol != null)
{
if ((itemsCol.Length > 0) && (itemsCol[0] != ""))
{
// counter to validate returnValue
int counter = - 1;
for (int i = 0; i < itemsCol.Length; i++)
{
string buf = itemsCol[i];
string[]itemsTokens = buf.Split('|');
// Check if already added to the collection
ListItem it = this.Items.FindByValue(itemsTokens[1]);
if (it == null)
{
string text = itemsTokens[0];
string id = itemsTokens[1];
ListItem item = new ListItem(text, id);
Items.Add(item);
// Updata counter
counter++;
}
}
returnValue = counter > - 1 ? true : false;
}
}
return returnValue;
}
The first set of code lines behaves as the code written for
the LoadPostData of the ListBox that ships with ASP.NET.
The second part retrieves all the indices that are listed in
the Hidden Field to be removed from the ListBox.
The third part retrieves all the item pairs (Text and Value)
that are found in the Hidden Field used to represent the items to be added to
the Items collection of the ListBox.
There is not much to be said about the
RaisePostDataChangedEvent method. The implementation is simple.
Listing 5
void IPostBackDataHandler.RaisePostDataChangedEvent()
{
OnSelectedIndexChanged(EventArgs.Empty);
}
What happens after the Page_Load method is fired? The
result of execution of the LoadPostData, which returns a Boolean value, is
checked. If the value if true, this means that the selected indices has
changed and, therefore, the need to raise the even called
OnSelectedIndexChanged.
On the other hand, if LoadPostData method returned a value
of false, this means that the selected indices have not been changed and then
there is no need to fire the OnSelectedIndexChnaged.
With the above said, we have finished implementing the new
smart ListBox control. In the next section we will see an example on how to
use this control on a web form and how to call the JavaScript utility methods
mentioned in a previous section.