SqlReader, Repeater controls and CommandArgument problem - c#

I have a repeater control that generates a list of links from a SqlReader. I'm trying to create a button alongside each link that will allow the user to delete that link. My original thought was to use the <%#Eval("URL") %> expression in the Item template like below. However the CommandArgument in the ItemCommand method would always come back empty.
<asp:Repeater ID="rptLinks" runat="server" onitemdatabound="rptLinks_ItemDataBound"
onitemcommand="rptLinks_ItemCommand">
<ItemTemplate><%# DataBinder.Eval(Container.DataItem, "URL") %><asp:ImageButton visible="false" ID="btnDeleteLink" runat="server" ImageUrl="/Images/DeleteIcon.gif" CommandName="DELETE" CommmandArgument=<%#Eval("URL") %> />
</ItemTemplate>
<SeparatorTemplate><br /></SeparatorTemplate>
</asp:Repeater>
The next thing I tried was to use the ItemDataBound event to programatically set the CommandArgument, but I can't figure out what to cast the e.Item.DataItem into so I can reference the ["URL"] Item.
protected void rptLinks_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
ImageButton btnDelete;
btnDelete = (ImageButton) e.Item.FindControl("btnDeleteLink");
if (btnDelete != null)
{
btnDelete.Visible = (bool)ViewState["LinkEditing"];
string URL = ((WhatTypeGoesHere)(e.Item.DataItem))["URL"].ToString();
btnDelete.CommandArgument = URL;
}
}

You can cast the DataItem to any of the classes in your reader's inheritance chain that implement IDataRecord:
// You could also cast to SqlDataReader, DbDataReader, or IDataReader
string URL = ((IDataRecord)(e.Item.DataItem))["URL"].ToString();
Data readers are a bit confusing, because objects that inherit from DbDataReader can act as both a data source (through its implementation of IEnumerable) and as the object representing your data (through its implementation of IDataRecord).
The IDataRecord interface provides access to the column values of a data reader's records (via the Item property and the various Get* methods).
In other words, it's like you're binding to an IEnumerable<IDataRecord> (though not really, because DbDataReader implements the non-generic version of IEnumerable).

Related

Populate DropDownList inside Grid Template Column

I have a dropdownlist inside a template column on a obout grid. Currently i am populating the dropdownlist on page load with a sqldatasource. However, i now have to load the dropdownlist dependent on the value of a certain column. For example: If status = 1, i populate the dropdownlist with a list of available options that pertain to status 1.
<obout:Column ID="colStatus" DataField="wf_status_id" Align="center" HeaderText="Status" HeaderAlign="center" Width="130px" Wrap="true" runat="server" AllowGroupBy="true" AllowFilter="true">
<TemplateSettings EditTemplateId="tmpStatusIDEdit" TemplateId="tmpStatusID" />
</obout:Column>
<obout:GridTemplate runat="server" ID="tmpStatusID" >
<Template>
<%# Container.DataItem["Status"]%>
</Template>
</obout:GridTemplate>
<obout:GridTemplate runat="server" ID="tmpStatusIDEdit" ControlID="ddlStatus" ControlPropertyName="value">
<Template>
<obout:OboutDropDownList runat="server" ID="ddlStatus" Width="100%" Height="200" MenuWidth="215" DataSourceID="sdsStatus" DataTextField="wf_status_text" DataValueField="wf_status_id" />
</Template>
</obout:GridTemplate>
public void OnGridRowDataBound(object sender, Obout.Grid.GridRowEventArgs e)
{
if (e.Row.RowType == Obout.Grid.GridRowType.DataRow)
{
DropDownList ddlStatus = new DropDownList();
ddlStatus = (DropDownList)e.Row.FindControl("ddlStatus");
//LOAD DROP DOWN HERE//
}
}
When i attempt to execute this code, it shows that ddlStatus is null everytime. I have a tried a multitude of ways to get this and for some reason cannot seem to get it. Perhaps aother set of eyes or other ideas could help me out. Please let me know what it is i am doing wrong. Thank you ahead of time
UPDATE:DATABOUND EVENT CODE
<obout:OboutDropDownList runat="server" ID="ddlStatus" Width="100%" Height="200" MenuWidth="215" OnDataBinding="ddlStatus_DataBinding" DataSourceID="sdsStatus" DataTextField="wf_status_text" DataValueField="wf_status_id" />
protected void ddlStatus_DataBinding(object sender, EventArgs e)
{
Obout.Interface.OboutDropDownList ddl = (Obout.Interface.OboutDropDownList)(sender);
string statusID = Eval("wf_status_id").ToString();
}
I added the DataSource because i do not see another way to have the databinding event triggered.
I don't really know anything about obout controls but I have to assume they act very similar to the asp.net controls and have just been extended. With that assumption in mind, I will try and answer your question.
Your RowDataBound event has a few coding issues... for example, I am not sure why you are defining a new DropDownList and then trying to overwrite it with the next line. Also it sounds like the next line is returning null anyways.
First off I suggest not using the DataBound event at the row level. Use the control's DataBinding event as it will localize your code a lot better because you can trigger off the specific control's DataBinding and therefore not have to search for it. If your code changes (markup or codebehind) it is also a lot easier to change as it will not affect other things and there is less room for introducing bugs.
So I would make the following changes to address this:
Change your DropDownList definition to implement DataBinding:
<obout:OboutDropDownList runat="server" ID="ddlStatus" Width="100%" Height="200"
MenuWidth="215" OnDataBinding="ddlStatus_DataBinding" />
Then implement the OnDataBinding event (get rid of your DataBound event if you weren't using it for anything else):
protected void ddlStatus_DataBinding(object sender, System.EventArgs e)
{
// This will point to ddlStatus on the current row that is DataBinding so you
// don't have to search for it.
OboutDropDownList ddl = (OboutDropDownList)(sender);
// Now you can fill the DropDownList and set the default value how ever you like
...
}
You can also see this other question I answered a long time ago to see if it helps as it is doing the same thing but with a Repeater but it is pretty much the same thing as a grid:
Populating DropDownList inside Repeater not working
EDIT: Changed the code to use OboutDropDownList in the DataBinding.
you can find plenty of samples on obout knowledge base and examples. These should help you out: http://www.obout.com/combobox/aspnet_integration_grid.aspx, http://www.obout.com/grid/aspnet_ajax_cascading_comboboxes.aspx
(they refer to comboBox, but you can easily adapt them do a ddl)

Trying to use a variation on the name of a parent page serving up a .net user control as the SelectMethod for a datasource

I am trying to build a reusable control (ascx) that can be used in multiple aspx pages. I have a datasource in the control which has a SelectMethod. Id like to use the calling page name (minus the extension) as the name of the SelectMethod - which can be looked up elsewhere.
Not sure how I would access this information from the ascx page. Was hoping something like this pseudo-code would work:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="Parent.pagename()" TypeName="BlahBlah"></asp:ObjectDataSource>
Where pagename() is a function in the .ascx.cs file returning the parent aspx page name as a string which can be looked up as the SelectMethod elsewhere in the ObjectContextFacadeManager in the BLL (its a large behemoth application - only half of which I am aware of).
Cheers.
You can get the value you're looking for using the AppRelativeCurrentExecutionFilePath. To output it you may have to use code-behind, though, because using inline-script, such as:
SelectMethod="<%Request.AppRelativeCurrentExecutionFilePath%>"
Won't work as the attribute value of a control with runat="server" (IIRC).
So, on load, or some other event, you could set this programmatically:
Page_Load(object sender, EventArgs e) {
SelectMethod = System.IO.Path.GetFileNameWithoutExtension(
Request.AppRelativeCurrentExecutionFilePath);
}

Get entity object from CommandArgument in GridView RowCommand

I am using a GridView which is bound to a List<Customer>. When RowCommand is fired by some button I want to be able to retrieve the current row's Customer object from the e.CommandArgument, like so:
protected void GridView_RowCommand(object sender, GridViewCommandEventArgs e)
{
Customer customer = (Customer)e.CommandArgument;
DoSomething(customer);
}
How do I assign the Customer object to CommandArgument before the event is fired?
I am not sure you can actually store a complex object in the CommandArgument as it seems to only take string or numeric values.
Something, which I have never really put into practice, is to convert your object into a Json string and use this as your command argument.
For example, using Newtonsoft.Json and a dummy object called FooBar
<asp:Button ID="btnOne" runat="server"
CommandName="Click"
CommandArgument='<%#Newtonsoft.Json.JsonConvert.SerializeObject((FooBar)Container.DataItem) %>'
Text="Click" />
Then when you handle the GridView RowCommand click event, you can Deserialize the object from the CommandArgument
FooBar fooBar = Newtonsoft.Json.JsonConvert.DeserializeObject<FooBar>(e.CommandArgument.ToString());
Now this works, but whether it is the best solution, I am not sure.

Pass object as CommandArguement in a Repeater Link Button

I have a Repeater with a list of Customers. Against each customer there is a delete link button. As part of the linkbutton I want to pass the Customer object to the Command Arguement as follows (where Container.DataItem is the customer object):
<asp:LinkButton ID="lnkDelete"
OnClientClick="return confirmDelete();"
OnClick="Customer_OnDelete"
CommandArgument="<%# Container.DataItem %>"
CommandName="Delete"
runat="server"></asp:LinkButton>
When I do this:
var button = (((LinkButton) sender));
var customer= button.CommandArgument;
button.CommandArguement is a string. I need all the object properties as we are using Nhibernate so everything needs to be set, the ID of the deleted record is not enough. I have seen examples online regarding passing a comma seperated list of values into the command arguement but want to avoid doing that. Is this possible?
Any ideas?
Thanks
In my opinion the best way for this case is:
Get the ID from CommandArgument
Get the Customer by ID
Delete the Customer Entity
Use the Repeater event OnItemCommand. This event contains RepeaterCommandEventArgs. You cant get the CommandArgument this way:
protected void myRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
int customerID= Convert.ToInt32(e.CommandArgument.ToString());
}
At your asp:LinkButton tag use:
CommandArgument='<%# DataBinder.Eval(Container.DataItem, "ID") %>'
The issue you are running into here is that you repeater has to get translated into HTML. Therefore you are constrained to the limits of what is allowed by the specification in an element attribute.
On the server side CommandArgument will always be a string, so you cannot do what you want as you have it coded.
Now... there are several hacks you could implement to get around this, like the aforementioned CSV, or you could use binary serialization and Base64 encode the result. However, these are all terrible solutions!
What you need is to re-think how you are doing this. I promise there is an easier way.

static variables as Header of TemplateFields in grdiv view asp.net

I have the asp.net application where I am having the editable grid view with the edit,Delete,Add options. this grid having as usual Template fields. I have also a static Class that having static string variables. I want to keep these static variable's value as Header text of Template Field.
So I have imported my constant class's namespace by :
<%# Import Namespace="ConstantManagerNamespace" %>
Then I tried for same column:
1. <asp:TemplateField HeaderText=<%=ConstantManager.Name%>>
2. <asp:TemplateField HeaderText='<%=ConstantManager.Name%>'>
3. <asp:TemplateField HeaderText=<% ConstantManager.Name %>>
4. <asp:TemplateField HeaderText='<% ConstantManager.Name%>'>
all probable syntax to access my constant variable value but
I got Parser error:
Literal content ('<asp:TemplateField HeaderText=') is not allowed within a 'System.Web.UI.WebControls.DataControlFieldCollection'.
how to do this ?
The problem occurs because you are trying to embed server-side control/value inside another server-side control. That is not directly possible in asp.net, unless you use databinding or custom expression builder.
For your exact situation, you need to create a custom expression builder, which returns the value from your static class.
Final result should look something like this:
<asp:TemplateField HeaderText="<$ ConstantManager:Name >">
Which is absolutely allowed withing aspx file as long as you have defined the custom expression builder with "ConstantManager" prefix.
The actual example of creating the custom expression builder can be found here: ExpressionBuilder Class.
ADDITION:
Also, I think databinding will also work, but it seems to me not the exact solution for this kind of situation.
Just use this syntax in the aspx markup:
<asp:TemplateField HeaderText="<# ConstantManager.Name >">
And, on page load, call:
protected void Page_Load(object sender, System.EventArgs e)
{
this.DataBind();
}
Personally I don't like this solution because of the Page_Load part. Anyway, this does not need to have anything special declared/coded if compared to the custom expressions.
I hope this helps!
Its better to bind the static class varibles in the GridView RowDataBound Event,
check the Row type is Header ie.
if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells[0].Text = ConstantManager.Name;
}

Categories

Resources