Persist Table Control Row Selection

A demonstration of extension over customization.

Introduction

ISD’s table controls have built-in row selection checkboxes, which do not remember their checked states on filtering, sorting or paging. This behavior is undesirable in some cases. This article will show a solution to persist row selection on filtering, sorting and paging. More importantly, it also demonstrates that extension is better than customization.

Solution by Customization

Below is the custom code to implement the functionality for a table control named OrdersTableControl.

public class OrdersTableControlRow : BaseOrdersTableControlRow {

  public OrdersTableControlRow() {
    Init += new EventHandler(OrdersTableControlRow_Init);
    PreRender += new EventHandler(OrdersTableControlRow_PreRender);
  }

  void OrdersTableControlRow_PreRender(object sender, EventArgs e) {
    OrdersRecordRowSelection.Checked =
      MyAppSession.SelectedRows.Contains(RecordUniqueId);
  }

  void OrdersTableControlRow_Init(object sender, EventArgs e) {
    OrdersRecordRowSelection.CheckedChanged +=
      new EventHandler(OrdersRecordRowSelection_CheckedChanged);
  }

  void OrdersRecordRowSelection_CheckedChanged(object sender, EventArgs e) {
    if (OrdersRecordRowSelection.Checked)
      MyAppSession.SelectedRows.Add(RecordUniqueId);
    else
      MyAppSession.SelectedRows.Remove(RecordUniqueId);
  }
}

public class OrdersTableControl : BaseOrdersTableControl {
  public OrdersTableControl() {
    Init += new EventHandler(OrdersTableControl_Init);
  }

  void OrdersTableControl_Init(object sender, EventArgs e) {
    // Clear selection on initial page load
    if (!Page.IsPostBack)
      MyAppSession.SelectedRows.Clear();
  }
}

MyAppSession.SelectedRows is an intellisensified session variable defined in another file, as shown below.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;

namespace SelectionDemo.UI {
  /// <summary>
  /// MyAppSession provides access to session variables as static properties.
  /// </summary>
  public class MyAppSession {
    /// <summary>
    /// Private shortcut to HttpContext.Current.Session. Check its availability.
    /// </summary>
    private static HttpSessionState currentSession {
      get {
        if (HttpContext.Current.Session == null)
          throw new Exception("Session is not available in the current context.");
        else
          return HttpContext.Current.Session;
      }
    }

    private static string selectedRowsKey = "selectedRowsKey";
    public static HashSet<string> SelectedRows {
      get {
        if (currentSession[selectedRowsKey] == null)
          currentSession[selectedRowsKey] = new HashSet<string>();
        return currentSession[selectedRowsKey] as HashSet<string>;
      }
    }
  }
}

Please note that this is just for a particular table control. If you need the functionality on other table controls, cut and paste the above code, and change control names accordingly.

Solution by Extension

Using the extension framework outlined in a previous article, we can implement the functionality in BaseTableControl and BaseRecordControl.

In BaseTableControl:

[Category("Behavior")]
[Description("Remember row selection")]
[TypeConverter(typeof(bool))]
[DefaultValue(false)]
public bool PersistRowSelection {
  get { return ViewState["PersistRowSelection"] != null; }
  set {
    if (value)
      ViewState["PersistRowSelection"] = value;
    else
      ViewState.Remove("PersistRowSelection");
  }
}

string SelectedRowsKey {
  get { return GetType().Name + "SelectedRows"; }
}

public BaseTableControl() {
  Init += new System.EventHandler(BaseTableControl_Init);
}

void BaseTableControl_Init(object sender, System.EventArgs e) {
  if (!Page.IsPostBack && PersistRowSelection) {
    HttpContext.Current.Session[SelectedRowsKey] = new HashSet<string>();
  }
}

public string[] GetSelectedRecordIDs() {
  if (!PersistRowSelection)
    throw new Exception("Row selection is not persisted.");

  HashSet<string> set = 
    HttpContext.Current.Session[SelectedRowsKey] as HashSet<string>;
  return set.ToArray();
}

In BaseRecordControl:

internal string GetRecordUniqueId() {
  return GetType()
          .GetProperty("RecordUniqueId")
          .GetValue(thisnullas string;
}

internal CheckBox GetRowSelectionCheckBox() {
  string name = GetType().Name.Replace("TableControlRow""RecordRowSelection");
  return FindControl(name) as CheckBox;
}

HashSet<string> SelectedRows {
  get {
    string key = GetType().Name.Replace("Row""SelectedRows");
    return HttpContext.Current.Session[key] as HashSet<string>;
  }
}

public BaseRecordControl() {
  Init += new System.EventHandler(BaseRecordControl_Init);
  PreRender += new EventHandler(BaseRecordControl_PreRender);
}

void BaseRecordControl_PreRender(object sender, EventArgs e) {
  if(SelectedRows != null){
    GetRowSelectionCheckBox().Checked =
      SelectedRows.Contains(GetRecordUniqueId());
  }
}

void BaseRecordControl_Init(object sender, System.EventArgs e) {
  if (SelectedRows != null) {
    CheckBox box = GetRowSelectionCheckBox();
    if (box == null)
      throw new Exception("Cannot find row selection checkbox.");

    box.CheckedChanged += new EventHandler(RowSelection_CheckedChanged);
  }
}

void RowSelection_CheckedChanged(object sender, EventArgs e) {
  if (GetRowSelectionCheckBox().Checked)
    SelectedRows.Add(GetRecordUniqueId());
  else
    SelectedRows.Remove(GetRecordUniqueId());
}

The above code will add row selection persistence to ALL table controls. To turn it on, it is as simple as setting a TableControl’s custom property PersistRowSelection to True.

Of course, you cannot use ISD’s GetSelectedRecords() method to get the selection when persistence is turned on. Instead, you should use the newly defined method GetSelectedRecordIDs().

Conclusion

Persisting table row selection is as simple as setting PersistRowSelection =
True after implementing this extesion.

One Response to “Persist Table Control Row Selection”

  1. Michael Valverde Says:

    Thank you so much! This was exactly what I was looking for!

    Mike

Leave a reply to Michael Valverde Cancel reply