A few weeks ago a StackOverflow user asked whether or not a RadGrid row could be selectable based upon some condition. I've run into scenarios in the past where this feature would have come in handy, but unfortunately the functionality is not provided in the RadGrid out of the box. However, as is common with Telerik components, it is possible to implement this functionality with a little extra effort.
First, let's start with a basic RadGrid and some data. For this example, we'll rely on our trusty friend Northwind and use LINQ to SQL and the LinqDataSource control to wire some customer data up to the grid.
<telerik:RadScriptManager ID="RadScriptManager1" runat="server" />
<telerik:RadGrid ID="rgCustomers" runat="server"
AllowMultiRowSelection="true"
DataSourceID="ldsCustomers">
<ClientSettings
EnableRowHoverStyle="true">
<Selecting AllowRowSelect="true" />
</ClientSettings>
<MasterTableView>
<Columns>
<telerik:GridClientSelectColumn UniqueName="SelectColumn" />
</Columns>
</MasterTableView>
</telerik:RadGrid>
<asp:LinqDataSource ID="ldsCustomers" runat="server"
ContextTypeName="RadGridConditionalClientSideRowSelection.Data.NorthwindDataContext"
TableName="Customers">
</asp:LinqDataSource>
I've allowed the grid to automatically generate its columns based on the data to which it is bound, and added an additional GridClientSelectColumn for selecting rows. Notice that I've also set the properties required to turn on client-side single- and multi-row selection. With those necessary first steps out of the way we can now implement the conditional selection functionality...
First, we need to add a property to the Customer entity that specifies whether or not a specific customer is selectable. Since we’re using LINQ to SQL, we can simply create a partial Customer class and add the new property as well
as the business rule used to determine the 'selectability' of the customer. For this example, let’s make all customers selectable except those from North America.
public partial class Customer
{
public bool IsSelectable
{
get { return this.Country != "USA" && this.Country != "Canada"; }
}
}
It shouldn't be too difficult to translate this to your own data model, regardless of whether you're using OpenAccess or some other ORM, or just good old fashion ADO.NET (e.g. if you're binding to a DataTable then just add the extra column and iterate through each row, setting each value based on your business rules). Once this extra value is added to our data model, we can easily track it with the RadGrid by adding it to the MasterTableView's ClientDataKeyNames collection. And since tracking it is only useful if we can access it when we need it - and we need it when a user attempts to select a record – we’ll add an event handler for the OnRowSelecting client-side event.
<telerik:RadGrid ID="rgCustomers" runat="server"
AllowMultiRowSelection="true"
DataSourceID="ldsCustomers">
<ClientSettings
EnableRowHoverStyle="true">
<ClientEvents OnRowSelecting="rowSelecting" />
<Selecting AllowRowSelect="true" />
</ClientSettings>
<MasterTableView
ClientDataKeyNames="IsSelectable">
<Columns>
<telerik:GridClientSelectColumn UniqueName="SelectColumn" />
</Columns>
</MasterTableView>
</telerik:RadGrid>
function rowSelecting(sender, args) {
var isSelectable = args.getDataKeyValue('IsSelectable') === 'True';
args.set_cancel(!isSelectable);
}
Since we’re automatically generating the columns displayed in the RadGrid, we'll need to hide the IsSelectable column. This can be avoided by setting the AutoGenerateColumns property of the RadGrid to false and defining each column in the grid manually. Or we can simply hide the column during the RadGrid's OnColumnCreated event.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
rgCustomers.ColumnCreated += new GridColumnCreatedEventHandler(rgCustomers_ColumnCreated);
}
protected void rgCustomers_ColumnCreated(object sender, GridColumnCreatedEventArgs e)
{
if (e.Column.UniqueName == "IsSelectable")
{
e.Column.Visible = false;
}
}
Now whenever a record is selected, we can retrieve the value of its IsSelectable property and either cancel the selection, or allow it to continue.
Okay, so these few easy tweaks get us 90% of the way there. However, this workaround will break the multi-select functionality and therefore we must also add a workaround to make it functional again. As you can see from the image below, the select all checkbox in the header remains unchecked after it is selected. This happens because our rowSelected event handler cancels the row selection for those rows which are not selectable, and internally this prevents the select all checkbox from being toggled. Therefore, you cannot uncheck the select all checkbox to deselect all rows again.

The workaround for this is fairly straightforward, but required a little digging into the RadGrid's client-side API and borrowing of its private functions in order to achieve the desired functionality. First, let's take a look at the code and then I'll discuss what it's doing.
function pageLoad() {
var tableView = $find('<%= rgCustomers.ClientID %>').get_masterTableView();
var headerRow = Telerik.Web.UI.Grid.getTableHeaderRow(tableView.get_element());
var checkBox = getSelectCheckBox(headerRow);
if (checkBox) checkBox.onclick = function(e) {
var event = e || window.event;
selectAllRows(checkBox.checked, event);
};
}
function selectAllRows(checkHeaderSelectCheckBox, event) {
var gridSelection = new Telerik.Web.UI.GridSelection();
var grid = $find('<%= rgCustomers.ClientID %>');
var tableView = grid.get_masterTableView();
var headerRow = Telerik.Web.UI.Grid.getTableHeaderRow(tableView.get_element());
grid._selectAllRows(tableView.get_id(), null, event);
gridSelection._checkClientSelectColumn(headerRow, checkHeaderSelectCheckBox);
}
function getSelectCheckBox(el) {
var inputs = el.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if (input.type.toLowerCase() !== 'checkbox')
continue;
if (input.id && input.id.indexOf('SelectCheckBox') != -1)
return input;
}
}
In the pageLoad function, I'm getting an instance of the MasterTableView's client-side object and retrieving it's header row element. Inside that element is the select all checkbox, which I retrieve using a bit of DOM traversal in the getSelectCheckBox function. I attach an onclick event handler, which calls the selectAllRows function, to the checkbox. This function mimics exactly what is happening behind the scenes in the RadGrid's client-side API, but changes the order in which things happen. You see, _selectAllRows must be fired before _checkClientSelectColumn; otherwise, when the rowSelecting event handler we defined cancels the row selection, the checkbox in the header will be left unchecked and break the multi-select/deselect functionality.
Now with the new workaround in place, the conditional row selection works like a charm (without breaking other functionality).

Hopefully my explanation of the code above is clear. If not, I highly recommend you dig into the RadGrid's client-side source code yourself and investigate how the row selection functionality works (specifically, take a look at the following RadGrid source files: GridCommon.js, GridSelection.js, and RadGrid.js). Remember, if you own a Telerik subscription license you have access to the source code as well. Reading and understanding how the controls are implemented provides quite a bit of clarity and is an immense amount of help to me when I find the need to implement workarounds such as this.
I think it would be nice to see Telerik implement conditional row selection in future versions of the RadGrid. But until then, they've provided a flexible enough client-side framework to allow us to implement such features with a minimal amount of effort. That's why I continue to use them in my own projects and recommend them to others.
[Source Code]
