RadzenDataFilter - Able to filter on string but filter doesn't seem to work with Lookup - radzen

I have attempted to replicate the Filtering via a lookup here - https://blazor.radzen.com/datafilter
My code uses a Lookup from our Db, not content from the returned query so it's only just slightly different but I cannot get the filtering to work when used with my Lookup. I have replicated the Radzen code whereby the Id is pulled right from the returned data set but when I use my Lookup I get this error.
No generic method 'Contains' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
For troubleshooting, in my OnSelectedLanguageIdsChange() I added a console.WriteLine and can confirm that the content of selectedLanguageIds are int.
At this point I'm lost...
<RadzenDataFilter #ref="dataFilter" TItem="Entity.Media" Auto=#auto Data="#medias"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" ViewChanged=#(view => filteredMedias = view.ToList())>
<Properties>
<RadzenDataFilterProperty TItem="Entity.Media" Property="Title" Title="Title" />
<RadzenDataFilterProperty TItem="Entity.Media" Property="Id" Title="ID" FilterValue="#selectedIds"
Type="typeof(IEnumerable<int>)" FilterOperator="FilterOperator.Contains">
<FilterTemplate>
<RadzenDropDown #bind-Value=#selectedIds Style="width:100%;"
Change=#OnSelectedIdsChange Data="#(mediaIds)" AllowClear="true" Multiple="true" />
</FilterTemplate>
</RadzenDataFilterProperty>
<RadzenDataFilterProperty TItem="Entity.Media" Property="languageId" Title="Language" FilterValue="#selectedLanguageIds"
Type="typeof(IEnumerable<int>)" FilterOperator="FilterOperator.Contains">
<FilterTemplate>
<RadzenDropDown #bind-Value=#selectedLanguageIds Style="width:100%;"
Change=#OnSelectedLanguageIdsChange AllowClear="true"
Data=#_languages Multiple=true TValue="IEnumerable<int>"
TextProperty="Name"
ValueProperty="Id" />
</FilterTemplate>
</RadzenDataFilterProperty>
</Properties>
<RadzenDataGrid #ref="mediasGrid" AllowPaging="true" AllowSorting="true" Data="#(filteredMedias ?? medias)" TItem="Entity.Media"
ColumnWidth="200px" PageSize="20" Style="height: 500px">
<Columns>
<RadzenDataGridColumn Width="5%" TItem="Entity.Media" Title="#" Filterable="false" Sortable="false" TextAlign="TextAlign.Center" Frozen=true>
<Template>
#(medias.IndexOf(context) + 1)
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Entity.Media" Property="Title" Title="Title" Width="25%" Visible="true" />
<RadzenDataGridColumn TItem="Entity.Media" Property="LanguageId" Title="Language" Width="15%" Visible="true" />
</Columns>
#code {
bool auto = true;
readonly MediaSearchViewModel _model = new();
RadzenDataFilter<Entity.Media> dataFilter;
IList<Entity.Media> filteredMedias;
IList<Entity.Media> medias;
RadzenDataGrid<Entity.Media> mediasGrid;
IEnumerable<LookupModel> _languages;
IEnumerable<int> selectedLanguageIds;
IEnumerable<int> selectedIds;
IEnumerable<int> mediaIds;
protected override async Task OnInitializedAsync()
{
await Lookups();
medias = await MediaService.SearchFiltered();
mediaIds = medias.Select(o => o.Id).Distinct();
}
private async Task Lookups()
{
_languages = await LanguageService.Lookup();
}
#region Filters
void OnSelectedLanguageIdsChange(object value)
{
if (selectedLanguageIds != null && !selectedLanguageIds.Any())
{
selectedLanguageIds = null;
}
foreach (var item in selectedLanguageIds)
{
Console.WriteLine(item);
}
}
void OnSelectedIdsChange(object value)
{
if (selectedIds != null && !selectedIds.Any())
{
selectedIds = null;
}
}
#endregion
}

Related

How to initialise data model before insert in ASP.net FormView

I have created a simple FormView in ASP.net 4.5
<asp:FormView runat="server"
ItemType="Wms.Models.GuiComponent"
DataKeyNames="GuiComponentId"
DefaultMode="Insert"
SelectMethod="GetItem"
InsertMethod="InsertItem"
RenderOuterTable="false">
<InsertItemTemplate>
<div class="form-container">
<asp:HiddenField runat="server" ID="TypeId" Value="<%# BindItem.TypeId %>"/>
<div class="row">
<asp:Label runat="server" AssociatedControlID="Reference">Reference</asp:Label>
<asp:TextBox runat="server" ID="Reference" TextMode="SingleLine" Text="<%# BindItem.Reference %>" />
</div>
<div class="controls margin-top-05">
<asp:Button ID="btnSubmit" Text="Create" CommandName="Insert" ValidationGroup="GuiComponent" runat="server" />
</div>
</div>
</InsertItemTemplate>
</asp:FormView>
I would like to be able to pre-populate some of the fields (e.g. TypeId in the above example) so that a complete model is returned to InserItem() method, and also because pre-populating some fields improves/helps the user experience (common default values for example). I had thought/hoped that the FormView's SelectMethod would do this, but apparently it doesn't.
// This method is not called for the InsertItemTemplate
public GuiComponent GetItem()
{
return new GuiComponent
{
// Initialise properties here
TypeId = GuiType.GuiComponentTypeId
};
}
public void InsertItem()
{
var model = new GuiComponent();
try
{
TryUpdateModel(model);
if (ModelState.IsValid)
{
GuiComponentService.Insert(model);
UnitOfWork.SaveChanges();
var url = String.Format("../../ComponentDetail.aspx?id={0}",
model.GuiComponentId);
Response.Redirect(url, false);
}
}
catch (DbEntityValidationException dbException)
{
ModelState.AddException(dbException);
}
catch (Exception ex)
{
ModelState.AddException("", ex);
}
}
I could, I suppose, initialise the controls on the form directly, but this seems cumbersome.
Does anyone know if there is a solution to this?
This is an old question but:
Use the form view IntemInserting method. So, to set TypeID you would do something like:
protected void FormView_ItemInserting(object sender, FormViewInsertEventArgs e)
{
e.Values["TypeId"] = TheDefaultValue;
}

On data binding: LINQ to Entities does not recognize the method 'System.String ToString()' method

I'm using LINQ to Entities
My GridView is the following :
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" AllowPaging="True"
EmptyDataText="No Data" CellPadding="3" CellSpacing="1"
AllowSorting="True" OnPageIndexChanging="GridView1_PageIndexChanging" OnRowCancelingEdit="GridView1_RowCancelingEdit"
OnRowEditing="GridView1_RowEditing" OnRowUpdating="GridView1_RowUpdating" CssClass="gridview"
OnSorting="GridView1_Sorting" HorizontalAlign="Center">
<AlternatingRowStyle BackColor="#F0F0F0" />
<Columns>
<asp:BoundField HeaderText="ID" DataField="ID" ReadOnly="True" SortExpression="ID" />
<asp:BoundField HeaderText="Name" DataField="SoftwareName" SortExpression="Name" />
<asp:BoundField HeaderText="Key" DataField="Key" SortExpression="Key" />
<asp:BoundField HeaderText="Date" DataField="Date" ItemStyle-CssClass="date_td" SortExpression="Date"
ReadOnly="True">
<ItemStyle CssClass="date_td"></ItemStyle>
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton runat="server" ToolTip="edit" ID="EditButton" CommandName="Edit"
ImageUrl="~/images/edit.png" />
</ItemTemplate>
<EditItemTemplate>
<asp:ImageButton runat="server" ID="UpdateButton" ToolTip="Submit" CommandName="Update"
ImageUrl="~/images/ok.gif" />
<asp:ImageButton runat="server" ID="Cancel" ToolTip="Submit" CommandName="Cancel"
ImageUrl="~/images/cancel.gif" />
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton runat="server" ToolTip="Delete" ID="btnDelete" CommandName="cDelete"
ImageUrl="~/images/delete.png" OnCommand="OnDelete" CommandArgument='<%# Bind("id") %>'
OnClientClick="return confirm('Are you sure ?')" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<PagerSettings Mode="NumericFirstLast" />
</asp:GridView>
I fill the GridView with the following c# code :
private IQueryable SortGridView()
{
IQueryable<Softwares> softwares = Search();
if (softwares == null) return null;
string sortExpression = (ViewState["SortExpression"] as string) == null
? "ID"
: ViewState["SortExpression"] as string;
string lastDirection = (ViewState["SortDirection"] as string) == null
? "ASC"
: ViewState["SortDirection"] as string;
switch (sortExpression)
{
case "ID":
softwares = (lastDirection == "ASC")
? softwares.OrderBy(q => q.id)
: softwares.OrderByDescending(q => q.id);
break;
case "Name":
softwares = lastDirection == "ASC"
? softwares.OrderBy(q => q.softwareName)
: softwares.OrderByDescending(q => q.softwareName);
break;
case "Key":
softwares = (lastDirection == "ASC")
? softwares.OrderBy(q => q.Keys.Key)
: softwares.OrderByDescending(q => q.Keys.Key);
break;
case "Date":
softwares = lastDirection == "ASC"
? softwares.OrderBy(q => q.Date)
: softwares.OrderByDescending(q => q.Date);
break;
}
return from q in softwares
select new
{
ID = q.id,
SoftwareName = q.softwareName,
Key = q.Keys.Key
Date = q.Date.ToString()
};
}
protected void ButtonSearch_Click(object sender, EventArgs e)
{
GridView1.DataSource = SortGridView();
GridView1.DataBind();// <<--- Exception
}
But in ButtonSearch_Click I get the following exception :
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression
I've done it before with the LINQ to SQL without any problems, what is wrong with it here?
LINQ to Entities queries are internally converted into sql statements. In your case its just that, LINQ to Entity provider is not able to map the "toString" call into a suitable SQL statement. You can retrieve the data from LINQ to entity and then enumerate offline and make the necessary changes i.e. :
var data = (from q in softwares
select new
{
ID = q.id,
SoftwareName = q.softwareName,
Key = q.Keys.Key
Date = q.Date
}).ToList();
and then convert the Date part by calling ToString() method offline.
data.ForEach(item => item.Date = item.Date.ToString());
You are returning anonymous type from your method. Anonymous types are accessible only within the class where they are defined. You can try something like the code I have given below :
private IList<SoftwareInfo> SortGridView()
{
// regular code
return (from q in softwares
select new SoftwareInfo
{
ID = q.id,
SoftwareName = q.softwareName,
Key = q.Keys.Key,
Date = q.Date
}).ToList();
}
public class SoftwareInfo
{
public int ID {get;set;}
public string SoftwareName {get;set;}
public string Key {get;set;}
public DateTime Date {get;set;}
}
protected void ButtonSearch_Click(object sender, EventArgs e)
{
GridView1.DataSource = SortGridView();
GridView1.DataBind();// <<--- Exception
}

ASP.NET empty GridView & DetailView problem

I have this page with a GridView control inside that's bound to database. GridView has a command row for insert, delete and updating. The problem is that, since my database table is initially empty, I see an empty grid. I don't even see the command row in order to be able to insert anything into it.
I managed to solve this by checking for GridView row count and changing its display to InsertTemplate. But I'm wondering if there's a standard way of doing this, may it already has such functionality?
The same problem with DetailView.
Thanks
You can use the EmptyDataTemplate to handle inserting a new item if the grid's data source is initially empty.
Define your grid in the ASPX as follows:
<asp:GridView runat="server" ID="grid" AutoGenerateColumns="false"
OnRowCommand="grid_RowCommand">
<Columns>
<asp:ButtonField ButtonType="Link" CommandName="Add" Text="Add" />
<asp:BoundField DataField="Id" HeaderText="Id" />
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
</Columns>
<EmptyDataTemplate>
<asp:TextBox ID="CustomerFirstName" runat="server"></asp:TextBox><br />
<asp:TextBox ID="CustomerLastName" runat="server"></asp:TextBox><br />
<asp:Button ID="Save" Text="Save" runat="server" CommandName="EmptyAdd"
UseSubmitBehavior="False" />
</EmptyDataTemplate>
</asp:GridView>
A collection of Customer objects is used as the datasource for the grid.
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Bind the grid to a data source (empty for this example).
protected void Page_Load(object sender, EventArgs e)
{
var customers = new List<Customer> {};
grid.DataSource = customers;
grid.DataBind();
}
You can then handle the Add and EmptyAdd command in the grid_RowCommand event handler.
protected void grid_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "EmptyInsert")
{
}
if (e.CommandName == "Insert")
{
}
}

DevExpress AspxGridView filter in ObjectDataSource

Yet another problem with DevExpress AspxGridView :)
The context:
One Page
In the Page, a custom control
In the custom Control, a AspxDropDown
The AspxDropDown has a DropDownWindowTemplate
In the DropDownItemTemplate, I add a GridView and a paging/sorting/filtering enabled ObjectDataSource
When handling the selecting event of the ObjectDataSource, I should set filter parameters for the datasource. There filter parameters should come from the FilterRow of the AspxGridView (preferably using the AspxGridView.FilterExpression property).
The problem: the AspxGridView.FilterExpression property is not set to the proper values (set by the user).
Did anyone find a good implementation of what I'm trying to do here?
Thanks a bunch.
:)
I've finally managed to get around the problem.
Not a good solution, but, still, a way to work around it.
So.. The "solution" is to databind the grid on every AfterPerformCallback event.
void grid_AfterPerformCallback(object sender, ASPxGridViewAfterPerformCallbackEventArgs e)
{
((DevExpress.Web.ASPxGridView.ASPxGridView)sender).DataBind();
}
As I've said, it's not a good solution.
The answer per DevExpress is that the correct FilterExpression is updated when it is databound.
They allege that in BeforePerformDataSelect, you will see the correct value.
I have 1 grid that is hooked up to a SqlDataSource that is correctly doing this, and another that is not... So you're mileage may vary.
My second grid wasn't obeying this principal, so I integrated the other guy's concept rebinding in AfterPerformCallback(). The trick is to prevent double querying. This code also demonstrates how to hijack devexpress to build your own SQL. Obviously, this is from my working project, so use your imagination on functions that I have that you don't...
Here is the relevant html and code:
<dxwgv:ASPxGridView ID="grid" runat="server"
KeyFieldName="OrderID"
OnAfterPerformCallback="grid_AfterPerformCallback"
OnBeforePerformDataSelect="grid_BeforePerformDataSelect"
AutoGenerateColumns="True"
SettingsDetail-AllowOnlyOneMasterRowExpanded="true"
Settings-ShowFilterRow="true"
Settings-ShowFilterRowMenu="True"
SettingsBehavior-AllowSelectSingleRowOnly="true"
OnDetailRowExpandedChanged="Grid_DetailRowExpandedChanged"
Styles-Cell-Cursor="pointer"
SettingsBehavior-EnableRowHotTrack="true"
CssFilePath="~/App_Themes/Office2010Blue/{0}/styles.css"
CssPostfix="Office2010Blue"
SettingsPager-PageSize="<%# this._GridRowsPerPage %>"
SettingsBehavior-ColumnResizeMode="Control"
SettingsCustomizationWindow-PopupHorizontalAlign="WindowCenter"
SettingsCustomizationWindow-PopupVerticalAlign="WindowCenter"
SettingsCustomizationWindow-Width="300px"
Settings-ShowHorizontalScrollBar="true"
Width="<%# this._GetWidth() %>"
SettingsPager-AlwaysShowPager="true"
SettingsCookies-Enabled="true"
>
<Columns>
<dxwgv:GridViewDataColumn FieldName="PriorityType" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="basePatientID" Caption="PTID" />
<dxwgv:GridViewDataColumn FieldName="FirstName" />
<dxwgv:GridViewDataColumn FieldName="LastName" />
<dxwgv:GridViewDataColumn FieldName="Employer" />
<dxwgv:GridViewDataColumn FieldName="Insurer" />
<dxwgv:GridViewDataColumn FieldName="ClaimJurisdiction" Caption="Jurisdiction" />
<dxwgv:GridViewDataColumn FieldName="DOB" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="DateOfInjury" Caption="DOI" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="PostalCode" Caption="ZipCode" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="FirstCareDate" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="LastCareDate" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="IntakeStatus" />
<dxwgv:GridViewDataColumn FieldName="SchedulingNeeded" />
<dxwgv:GridViewDataColumn FieldName="InitialReferralDate" Caption="Date Assigned" />
<dxwgv:GridViewDataColumn FieldName="Orders_UpdatedOn" Caption="Last Follow-up" />
<dxwgv:GridViewDataColumn FieldName="RequestTypes" Caption="Service" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="FacilityGroups" Caption="Provider" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="ICD9Codes" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="CPTCodes" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="OrderCategory" Caption="Source" />
<dxwgv:GridViewDataColumn FieldName="CaseCoordinator" Visible="false" />
<dxwgv:GridViewDataColumn FieldName="SchedulingTier" Visible="false" Caption="Tier" />
<dxwgv:GridViewDataColumn FieldName="LockRequest_UserName" Visible="true" Caption="InUseBy" />
</Columns>
<Styles CssFilePath="~/App_Themes/Office2010Blue/{0}/styles.css" CssPostfix="Office2010Blue">
<Header ImageSpacing="5px" SortingImageSpacing="5px">
</Header>
<LoadingPanel ImageSpacing="10px">
</LoadingPanel>
</Styles>
<ImagesFilterControl>
<LoadingPanel Url="~/App_Themes/Office2010Blue/Editors/Loading.gif">
</LoadingPanel>
</ImagesFilterControl>
<Images SpriteCssFilePath="~/App_Themes/Office2010Blue/{0}/sprite.css">
<LoadingPanelOnStatusBar Url="~/App_Themes/Office2010Blue/GridView/gvLoadingOnStatusBar.gif">
</LoadingPanelOnStatusBar>
<LoadingPanel Url="~/App_Themes/Office2010Blue/GridView/Loading.gif">
</LoadingPanel>
</Images>
<ClientSideEvents ContextMenu="grid_ShowContextMenu" />
<ClientSideEvents BeginCallback="function(s, e) { OnBeginCallback(s,e); }" />
<ClientSideEvents EndCallback="function(s, e) { OnEndCallback(s,e); }" />
<StylesEditors>
<ProgressBar Height="25px">
</ProgressBar>
</StylesEditors>
</dxwgv:ASPxGridView>
<asp:SqlDataSource ID="GridSource" runat="server"></asp:SqlDataSource>
And here's the event handler for BeforePerformDataSelect:
private bool _DataBindingCompleted = false;
protected void grid_BeforePerformDataSelect(object sender, EventArgs e)
{
if (_DataBindCompleted) Grid_PerformDataSelect(sender, e);
}
protected override void Grid_PerformDataSelect(bool ClearSelection)
{
if (ClearSelection) this.grid.Selection.UnselectAll();
GridSource.ProviderName = System.Configuration.ConfigurationManager.ConnectionStrings["mysql"].ProviderName;
GridSource.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["mysql"].ConnectionString;
SetupSearch();
//if (this.FilterContext.Count > 0 || !string.IsNullOrEmpty(grid.FilterExpression))
//{
string FilterSQL = DevExpressUtils.GetMySQLFilterExpression(grid);
string OrderBySQL = DevExpressUtils.GetSQLOrderByExpression(grid, "OrderID");
//FilterSQL = FilterSQL.Replace("[PatientID]", "vwPatients."+ Patient.PRIMARYKEY);
if (Utils.GetAppSettingBool("MYSQL"))
{
GridSource.SelectCommand = this.MP.CurrentUser.GetEOSHeaderSQL(this.FilterContext, FilterSQL, "");
}
else
{
GridSource.SelectCommand = "";
}
}
protected override void Grid_PerformDataSelect(object sender, EventArgs e)
{
bool IsFromParent = this.ClientID.StartsWith(this.MP.GridCallback);
if (grid.Visible && (!this.Page.IsCallback ||
((this.MP.GridCallback == this.grid.ClientID && (this.MP.GridCallbackCommand != "SHOWDETAILROW" || this.IsDetailGrid))
|| (this.MP.GridCallbackCommand == "SHOWDETAILROW" && IsFromParent)
)
)
)
{
Grid_PerformDataSelect(false);
}
}
protected void grid_AfterPerformCallback(object sender, ASPxGridViewAfterPerformCallbackEventArgs e)
{
_DataBindCompleted = true;
((DevExpress.Web.ASPxGridView.ASPxGridView)sender).DataBind();
}
protected void Page_Init(object sender, EventArgs e)
{
grid.DataSource = GridSource;
}
protected new void Page_Load(object sender, EventArgs e)
{
this.grid.ClientInstanceName = this.grid.ClientID;
if (!this.IsPostBack)
{
_DataBindCompleted = true;
grid.DataBind();
}
}

ASP.Net GridView GridViewDeleteEventArgs.Keys empty

I have following Gridview:
<asp:GridView ID="GridView1" runat="server" CssClass="table" DataKeyNames="groupId"
DataSource="<%# dsUserGroupsSelected %>" DataMember="Group" etc....>
and after firing RowDeleting event handler:
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
e.Keys is empty. Moreover, in runtime if I check
dsUserGroupsSelected.Group.PrimaryKey
it is poulated with:
{System.Data.DataColumn[1]}
[0]: {groupId}
so it's really odd to me. Am I missing something? I have this kind of a workaround:
int groupId = (int)GridView1.DataKeys[e.RowIndex].Value;
which will work just fine, but I just can't get it why e.Keys (and e.Values) would be empty!? Any ideas?
It looks like this behaviour is intentional.
From http://forums.asp.net/p/1050092/2128091.aspx
Looking in Reflector at Gridview.HandleDelete(), it appears that
e.Keys and e.Values are only populated if
gridview.IsBoundUsingDataSourceID. That is, if you set the DataSource
in code then none of this will work. Good one, Microsoft! Might have
been useful to mention that in the help perhaps??!! Lachlan
Edit:
I ended up making my own data objects and put them in the app_code folder
ex.
public class CustomDataViews
{
public class FileQuery
{
public class File
{
public DateTime CreatedDate { get; set; }
public string FileName { get; set; }
public string Path { get; set; }
public void Delete() { }
}
public ArrayList GetFiles()
{
System.Collections.ArrayList files = new ArrayList();
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(HttpContext.Current.Server.MapPath("~/UserUpload/"));
foreach (System.IO.FileInfo fi in (from a in di.GetFiles() orderby a.CreationTime descending select a))
{
File myFile = new File();
myFile.CreatedDate = fi.CreationTime;
myFile.FileName = fi.Name;
myFile.Path = "/VACWeb/UserUpload/" + fi.Name;
files.Add(myFile);
}
return files;
}
public void Delete(string FileName)
{
if (FileName != null)
{
string path = HttpContext.Current.Server.MapPath("~/UserUpload/") + FileName;
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
}
}
}
}
aspx
<asp:GridView ID="gvFiles" runat="server" AutoGenerateColumns="False" DataKeyNames="FileName"
DataSourceID="ods1">
<Columns>
<cc:ExtendedCommandField DeleteConfirmationText="Are you sure you wish to delete this file?"
DeleteText="Delete" ShowDeleteButton="true" />
<asp:BoundField DataField="CreatedDate" HeaderText="Created Date" DataFormatString="{0:MM/dd/yyyy}" />
<asp:BoundField DataField="FileName" HeaderText="File Name" />
<asp:ImageField DataImageUrlField="Path" AlternateText="No Image" HeaderText="Image Preview"
ControlStyle-Width="100px">
<ControlStyle Width="100px" />
</asp:ImageField>
<asp:BoundField DataField="Path" HeaderText="Path" />
<asp:HyperLinkField DataNavigateUrlFields="Path" DataTextField="FileName" HeaderText="Link" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ods1" runat="server" DeleteMethod="Delete" SelectMethod="GetFiles"
TypeName="CustomDataViews+FileQuery">
<DeleteParameters>
<asp:Parameter Name="FileName" Type="String" />
</DeleteParameters>
</asp:ObjectDataSource>
Simple! ASP is a big piece of .... and GridView is a small piece in the big peace. Have the same problem, and while the workaround is ok for deleting, updating becomes really interesting... The actual problem is it seems that for no good or apparent reason a looooooooot of the functionality of GridView is missing if the DataSource is not a DataSourceControl: Like filling the keys & values properties in the eventargs. Enjoy! Viva Microsoft!
Is it possible you're programatically sorting your gridview in your Page_Load method? If so, try moving the sort into the Page_Init method, and see if that fixes the problem.
Apparently, the GridViewDeleteEventArgs.Keys property only works if you set the GridView's DataSource by setting the DataSourceID property -- i.e. setting the DataSource property and then manually calling DataBind() leaves the Keys property (and the Values property as well) empty.
Source: http://forums.asp.net/t/1050092.aspx

Resources