I do have two nested APSxGridView objects. The DetailRow in the inner one contains also a button. I want to initialize the button so that it launches new window in the browser. For that, I need the key id's from the upper GridViews.
GridView1
GridView2
DetailRow
Button
I already know how to get the key from the GridView2 -- my existing code looks like:
protected void btnModify_Init(object sender, EventArgs e)
{
ASPxButton btn = sender as ASPxButton;
GridViewDetailRowTemplateContainer clsdetail = btn.Parent as GridViewDetailRowTemplateContainer;
string partition = "1"; // this should be filled with the GridView1 id
string cls = clsdetail.KeyValue.ToString(); // this is the GridView2 id
// The following code just uses the information.
string panelid = "t" + partition + "-" + cls;
btn.ClientSideEvents.Click =
String.Format("function(s, e){{ window.open('producttag.aspx?partition={0}&cls={1}','{2}'); }}",
partition, cls, panelid);
}
Notice the string cls = ... that gets the key from the inner grid (the button is inside its detail row).
How can I get the key for the outer gridview? Can I do it through parents again? Or is there any other way?
Update: More than one detail row can be expanded in the inner grid view. This way, I cannot pass the id's through some hidden element. I need to get it being at the button level from the upper objects.
OK. I have found it -- use NamingContainer:
ASPxButton btn = sender as ASPxButton;
GridViewDetailRowTemplateContainer clsdetail = btn.NamingContainer as GridViewDetailRowTemplateContainer;
Control gvClasses = clsdetail.Grid; // the grid 2
Debug.Assert(gvClasses.ClientID.EndsWith("gvClasses"));
GridViewDetailRowTemplateContainer partitionsdetail = gvClasses.NamingContainer as GridViewDetailRowTemplateContainer;
// the upper is the detail row of the grid 1
string partition = partitionsdetail.KeyValue.ToString(); // from grid 1
string cls = clsdetail.KeyValue.ToString(); // from grid 2
Related
The asp:GridView displays the order lines. It contains only two BoundFields: ID (not visible) and html_text_info (visible). The gvOrderLines.DataSource is explicitly assigned by the DataTable that was obtained by calling the SQL stored procedure. Before that,the html_text_info is added to the DataTable, and it is filled by the formatted HTML text where other columns are the source for the information. See the following method (simplified):
private void LoadGridViewOrderLines()
{
// Get the data table with the order-line data for the order.
DataTable dt = DbUtil.GetAppTable(
"usp_order_lines #order_code=#order_code",
new Hashtable { { "order_code", OrderCode } },
commandTimeoutSeconds: 180);
// Add the field html_text_info, and format the info into it.
dt.Columns.Add("html_text_info", typeof(string));
StringBuilder sb = new StringBuilder();
foreach (DataRow row in dt.Rows)
{
sb.Clear();
// Get the values from the row.
string product_code = row.Field<string>("product_code");
string product_name = row.Field<string>("product_name");
double quantity = ... get the quantity and convert to double...;
string unit = row.Field<string>("unit");
double price = ... get the price and convert to double...;
// Format it as an HTML string.
sb.Append($"{product_code}<br />");
sb.Append($"<b>{product_name}</b><br />");
sb.Append($"Quantity: <b>{quantity:f2} {unit}</b><br />");
sb.Append($"Price: <b>{price:f3}</b><br />");
// Set the formatted value to the field.
row["html_text_info"] = sb.ToString();
}
gvOrderLines.DataSource = dt;
gvOrderLines.DataBind();
}
Now, I want to edit/update the order item. So, I need to access the row from the DataTable that is used as the DataSource. I already have the handler that gets correctly the ID into the property UpdateID (because it was named as DataKeyNames="ID" for the grid view; see below). How can I get the source values that form the composed field?
protected void gvOrderLines_RowEditing(object sender, System.Web.UI.WebControls.GridViewEditEventArgs e)
{
UpdateID = (int)gvOrderLines.DataKeys[e.NewEditIndex].Value;
// How to get the source values that form the composed field?
tbCode.Text = ???;
tbName.Text = ???;
tbQuantity.Text = ???;
tbPrice.Text = ???;
gvOrderLines.EditIndex = -1; // cancel
gvOrderLines.DataBind();
}
Is the DataRow for current e.NewEditIndex easily accessible? Or do I have to search on my own in the DataTable (that is the gvOrderLines.DataSource)?
The "data row" source ONLY persists during the data binding operations.
So for example, you have "looping" code after you pull the data to on the fly create those extra columns. I often do that, but I still in most cases would suggest you do that "one row" operation in the gv, and not against the table.
This suggestion is not a "must" do, but it can help. Since then you are free to have other buttons, filters or whatever and JUST toss/pass/send/throw to the gv the data source. (so, each time you pull/create/have/use/filter etc. the data source, you don't have to modify it with that extra column.
Thus this:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gData = e.Row.DataItem as DataRowView; // the data source row!!!!
Label Info = (Label)e.Row.FindControl("lblInfo");
StringBuilder sb = new StringBuilder();
sb.Clear();
// Get the values from the row.
string product_code = gData["product_code"].ToString();
string product_name = gData["product_name"].ToString();
double quantity = ... get the quantity and convert to double...;
string unit = gData["unit"].ToString();
double price = ... get the price and convert to double...;
// Format it as an HTML string.
sb.Append($"{product_code}<br />");
sb.Append($"<b>{product_name}</b><br />");
sb.Append($"Quantity: <b>{quantity:f2} {unit}</b><br />");
sb.Append($"Price: <b>{price:f3}</b><br />");
// Set the formatted value to the field.
Info.Text = sb.ToString();
}
}
however, as I stated/noted, the so-called data source (dataitem) that seems to show all over the place in most GV events, is ONLY persisted during the binding process. Once binding is done, then that data item goes out of scope.
Next up, a button click to edit/get the one row.
I (now) in most cases do NOT bother with the gv event model WHEN most of the code and editing is custom code (code you the developer is writing and wanting control of what the heck is going to occur!!!).
So, just drop in a plane jane button into the grid row, and use a plane jane standard button click event.
Say, like this:
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
<asp:BoundField DataField="Description" HeaderText="Description" ItemStyle-Width="270" />
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit"
CssClass="btn" OnClick="cmdEdit_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
So, note how I do (did not) bother with using the built in gv events.
So, the button click event - a plane jane one looks like this:
protected void cmdEdit_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
GridViewRow gRow = btn.NamingContainer as GridViewRow;
int PKID = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
Debug.Print("row index click = " + gRow.RowIndex);
Debug.Print("database PK id = " + PKID);
string strSQL = "SELECT * FROM tblHotelsA WHERE ID = " + PKID;
DataRow rstData = MyRst(strSQL).Rows[0];
.. etc. etc.
From that row click, we get/use/have the database PK id, and thus have to re-pull the data. Note how we NEVER exposed/used/have the database PK id in the gv markup - (for reasons of security). (and I see you ALSO using datakeys - good!!).
So, your edit button click (now a plane jane click event) becomes somthing like this:
protected void cmdEdit_Click(object sender, EventArgs e)
{
GridViewRow gRow = btn.NamingContainer as GridViewRow;
int PKID = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
// How to get the source values that form the composed field?
// answer: we re-pull the database row based on pk
int UpdateID = (int)gvOrderLines.DataKeys[e.NewEditIndex].Value;
string strSQL = "SELECT * FROM MyTable WHERE ID = " + UpdateID;
DataRow OneRow = MyRst(strSQL).Rows[0];
// any display value in gv - you use find control ,or cells[] collection
TextBox txtHotelName = gRow.FindControl("txtHotel") as TextBox;
Just remember that dataitem" is available ONLY during binding, and after the databinding to the gv is done, then it (the dataitem) goes out of scope.
If the value(s) you need are not in the gv "display", then you need to re-pull that one row for such values.
templated controls in gv - use find control
built in, use cells[] collection.
Now, to be fair, I don't much use the built in "edit" function, and I just drop in a simple edit button, and either hide the gv, show the hidden edit "div" I have. Or better yet, pop that div like this:
I'm dynamically creating a load of radiobuttons in code behind (vb.net on load) and am wondering how I should create the events on them. I have a gridview with two columns and each row has a radiobutton in both columns that are in a group together (fyi group means check one, the other is unchecked). I want to change the background colour to yellow on whichever one is checked. How best would I do this? Javascript (catch all radio button change events), JQuery (catch all radio button change events) or Vb.net (attach method on creation)? Here is how I'm creating them;
Dim r As RadioButton
Dim l As Label
Dim radioBtnNumber As Integer = 0
For row As Integer = 0 To GridView1.Rows.Count - 1
If GridView1.Rows(row).RowType = DataControlRowType.DataRow Then
Dim x As Integer = 0
For Each tc As TableCell In GridView1.Rows(row).Cells
l = New Label()
l.Text = tc.Text
If (x = 1) Or (x = 2) Then
r = New RadioButton()
r.GroupName = String.Format("RdBtnGroup{0}", row)
r.ID = radioBtnNumber.ToString
//Could add in event here. Tried this but didn't work
//r.Attributes.Add("OnCheckedChanged", "radiobuttonChecked()")
tc.Controls.Add(r)
radioBtnNumber = radioBtnNumber + 1
End If
tc.Controls.Add(l)
x = x + 1
Next
End If
Next
That code is actually more confusing that it should be because the gridview is actually flipped (veritical as opposed horizontal). So I have radiobuttons named 0, 1, 2, 3, 4 etc with 0 and 1 in a group, 2 and 3 in a group etc and I just want to catch which one has been changed. Bear in mind though that I need the name of the RB or it's position in my gridView as I'll have to change the background colour of the RB it's paired with also!
Add line (code is C#, translate to VB):
r.CheckedChanged += new System.EventHandler(this.radiobuttonChecked);
when you create the RadioButton. radiobuttonChecked should be method of your webpage:
protected void radiobuttonChecked(Object sender, EventArgs e)
{
...
}
where you will be able to cast sender to RadioButton and analyze its properties. This will cause a postback to the server, where you can modify the radio buttons.
If you want to do it on the client, then you can first assign CssClass (e.g. "rbClass") to the same string for all of them and also use
r.Attributes.Add("pairName", "<name for the pair of radiobuttons>")
Then add javascript to your page:
$(document).ready(function(){
$(".rbClass").change(function(){
// here you look at $(this).attr and
// adjust its and its pair's css accordingly
})
});
I Have Two Gridview in first one there is some data with checkbox. I Want when i check two or more checkboxes then show the both record who's checked to another gridview There is my Coding. Problem is it's show only one record at a time..
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
foreach(GridViewRow row in GridView1.Rows)
{
if (row.RowType == DataControlRowType.DataRow )
{
CheckBox chkSelect = (CheckBox)row.Cells[0].FindControl("CheckBox1");
if (chkSelect != null)
{
if (chkSelect.Checked)
{
string FoodItem = ((Label)row.FindControl("Label1")).Text.ToString();
string s = "select * from Item where Item_Name='" + FoodItem + "' ";
db.grid(s, GridView2);
}
}
}
}
By looking your code,
first think dont bind gridview immediately after checking checked property of each check box, it will override gridview2. first collect all check box values by concatinating say FoodItem = "(value1,value2,value3)".
call data base one time by modifying query like
string s = "select * from Item where Item_Name in " + FoodItem +";
db.grid(s, GridView2);
I think you have multiple selection so keep seperate button and write all codes to copy from one grid to another grid inside button click event.
i have a dropDownList which gets its data from a database. Now after the data has bound, i programmatically add another listItem to the ddl, like so:
protected void ddlEffects_DataBound(object sender, EventArgs e)
{
DropDownList ddl = dwNewItem.FindControl("ddlEffects") as DropDownList;
ddl.Items.Add(new ListItem("","0")); //Adds an empty item so the user can select it and the item doesnt provide an effect
}
It all works, but the problem is that the newly added listItem appears at the bottom of the DDL. I want it to be the first item. I tried making the value 0, but its still at the bottom. Is there any way to put it at the top?
Thanks!
Check into the ddl.Items.Insert method that will allow you to insert items at a specific location.
Like this for example:
using (Entities db = new Entities())
{
ddlDocumentTypes.DataSource = (from q in db.zDocumentTypes where (q.Active == true) select q);
ddlDocumentTypes.DataValueField = "Code";
ddlDocumentTypes.DataTextField = "Description";
ddlDocumentTypes.DataBind();
ddlDocumentTypes.Items.Insert(0, "--Select--");
ddlDocumentTypes.Items[0].Value = "0";
}
Which using EF loads the DDL with items for the database, and then inserts at position zero a new item.
my problem: how do I populate extra cells in my gridview during the runtime construction of the grid? (these cells are not bound to any datasource and all I want to do is show some custom text)
I have a gridview on my page and I get 2 columns as bound columns from a fixed database - let's call them
id and URL
I've added a couple of extra columns which are not bound to any datafield but I want to populate the cells with some text which is relevant to the id
for e.g. if the row 1 is
12 http://www.something.com
then I want the extra cell to have 'you have visited this 13 times'
12 http://www.something.com 'you have visited this 13 times'
this text comes from some internal processing I do.
What I want to do is to insert this text when the gridview is being constructed at run time..am totally clueless how to do this. I'm sorry if I'm asking a very dumb question..
You can use the OnRowDataBound event of the GridView to get the current DataItem's content and then set the value of your extra column. You could also just get the cell's content. I think using the DataItem is a bit better, but you can do either.
Something like below
protected void MyGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string myValue = e.Row.Cells[0].Text;
e.Row.Cells[3].Text = " you have visited this " + myValue + " times";
-- or --
MyObjectType myData = e.Row.DataItem as MyObjectType ;
Literal litText = e.Row.FindControl("litText") as Literal;
litText.Text = "you have visited this " + myData.PropertyName + " times";
}
}
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.onrowdatabound.aspx
http://www.nikhedonia.com/notebook/entry/how-to-show-some-rows-differently-in-a-gridview/
Any way to manipulate the columns in GridView with AutoGenerateColumns = true?