I am trying to check a CheckBox for certain rows in a GridView if there are records in the database. Lets say I have product 1,2,3,4 in a category and the products available for packaging are 1 and 3. Inside my GridView, for each category, I only checked the checkbox of product 1 and 3 instead of all the products in that category. Here is how I set up my GridView:
<!-- Collapsible panel extender body -->
<asp:Panel ID="pBody1" runat="server" CssClass="cpBody">
<asp:Label ID="lblBodyText1" runat="server" />
<!-- Grid view to show products based on each category -->
<asp:GridView ID="gvProduct" runat="server" AutoGenerateColumns="False" Width="998px" CellPadding="4" ForeColor="#333333" GridLines="None" ShowHeader="False" DataKeyNames="id">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<Columns>
<asp:TemplateField HeaderText="Select" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="cbSelect" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="name" HeaderText="Name" ItemStyle-Width="750px" />
<asp:BoundField DataField="categoryName" HeaderText="Category" />
<asp:BoundField DataField="inventoryQuantity" HeaderText="Quantity" />
</Columns>
</asp:GridView>
</asp:Panel>
And from the code behind, first I get all the products based on category. I named it as prodList. Then, I get all the products available for packaging. I named it as distSPUItemList. I loop thru both lists and if their name match, I get the row and check the checkbox:
List<ProductPacking> prodList = new List<ProductPacking>();
//Get all products based on category
prodList = prodPackBLL.getAllProductByCategory(category);
gv.DataSource = prodList;
gv.DataBind();
List<DistributionStandardPackingUnitItems> distSPUItemList = new List<DistributionStandardPackingUnitItems>();
distSPUItemList = packBLL.getAllSPUItemByDistributionID(distributionID);
for (int i = 0; i < distSPUItemList.Count; i++)
{
for (int j = 0; j < prodList.Count; j++)
{
GridView gvForCheckBox = (GridView)e.Item.FindControl("gvProduct") as GridView;
foreach (GridViewRow gr in gvForCheckBox.Rows)
{
if (prodList[j].name == distSPUItemList[i].name)
{
CheckBox cb = (CheckBox)gr.Cells[0].FindControl("cbSelect");
cb.Checked = true;
}
}
}
}
However, for the CheckBox, it just checks all the products inside that category instead of checking the one that match between prodList and distSPUItemList. Why is this?
I believe the best way to solve your problem is to determine if this CheckBox should be checked prior to Data Binding your "gvProduct" control. Setting this value in the Data Source ahead of time will prevent you from having to re-access the GridView later on.
If this is not an option, the solution below will work, but is more clunky since you have to re-access the GridView and then iterate its Row collection.
Disclaimer, done in my head without VS2012, so please forgive any minor syntax errors. I modified your code to remove parts that were not specifically relevant to this solution. First, get your two lists of objects:
List<ProductPacking> prodList = prodPackBLL.getAllProductByCategory(category);
List<DistributionStandardPackingUnitItems> distSPUItemList = packBLL.getAllSPUItemByDistributionID(distributionID);
Next, you can use a simple LINQ query to compare lists of objects finding ProductPacking objects whose name property are equal to the items in distSPUItemList. This creates a new collection of only objects that match:
var available = // Start with prodList
from a in prodList
// perform an inner-join between prodList and distSPUItemList only returning objects whose names match
// (x => x.name == a.name) compares b.name to a.name, this is specifically what enforces that names match.
from b in distSPUItemList.Where(x => x.name == a.name)
// after inner joining is done, only select objects from prodList (we could select more things, but we only need these.)
select a;
And lastly, you may iterate the gridview rows and see if the name property shown in the GridView was in the list of products available for packaging, if it was, mark the checkbox checked.
GridView gvForCheckBox = (GridView)e.Item.FindControl("gvProduct") as GridView;
foreach (GridViewRow gr in gvForCheckBox.Rows)
{
// query the available collection to see if it contains a ProductPacking object with a name equal to what is in the current GridView row.
// I would recommend to match on a PK
// disclaimer, matching on name may be a problem if two different products can have the same name.
if (available.Where(x=>x.Name==gr.Cells[1].Text).Any())
{
CheckBox cb = (CheckBox)gr.Cells[0].FindControl("cbSelect");
cb.Checked = true;
}
}
Related
I'm using ASP.net and i've added a delete button on a gridview and im trying to remove the row of the button clicked. The thing is though, that i get an InvalidOperationException on my foreach.
I may have other errors in the code or my logic may be wrong so if you see any of it please point them out. Thanks.
gridView cart.ASPX:
<asp:GridView ID="CartGrid" runat="server" AutoGenerateColumns="false" OnRowDeleting="RemoveSelected">
<Columns>
<asp:BoundField DataField="product_name" HeaderText="Name" />
<asp:BoundField DataField="price_per_unit" HeaderText="Price" />
<asp:BoundField DataField="unit" HeaderText="Unit" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="delSelected" runat="server" Text="Delete" CommandName="Delete"></asp:LinkButton>
</ItemTemplate>
<ItemStyle Width="100px" />
</asp:TemplateField>
</Columns>
</asp:GridView>
delete method cart.ASPX.CS
protected void RemoveBtn(object sender, GridViewDeleteEventArgs e)
{
ArrayList cartList = (ArrayList)Session["cartList"];
GridViewRow row = (GridViewRow)CartGrid.Rows[e.RowIndex];
String name = row.Cells[0].Text;
//String name = (string)CartGrid.DataKeys[e.RowIndex].Value;
//String name = CartGrid.SelectedRow.Cells[1].Text;
foreach (product p in cartList)
{
if (p.product_name.Equals(name))
{
cartList.Remove(p);
}
}
CartGrid.DataBind();
}
Hi I think the issue is that you are using the cartlist for loop and at the same time you want to delete values from the same which is not possible .
just you need to change your approach like create the empty list and add all the index into it from where you have to delete the value Staring from bottom to top like from end of list so that it can not effect the index of the list by deleted value and after loop you can delete it using the new empty list which contain the list of all the values which should be deleted.
You can't modify the collection you're iterating over with the foreach - please see this question for more information.
I'm having problems retrieving the current row by changing the status of a DropDownList in the row. My code for the GridView is:
<asp:GridView ID="grdMappingList" runat="server" OnPageIndexChanging="grdMappingList_PageIndexChanging" AutoGenerateColumns="false" AllowPaging="true" PageSize="10" ShowHeaderWhenEmpty="true" UseAccessibleHeader="true" CssClass="table table-hover table-striped segment_list_tbl" >
<PagerStyle CssClass="grid_pagination" HorizontalAlign="Right" VerticalAlign="Middle" BackColor="#DFDFDF" />
<Columns>
<asp:BoundField HeaderText="Mapping Id" DataField="MAPPING_ID"></asp:BoundField>
<asp:BoundField HeaderText="PDM Name" DataField="PDM_NAME"></asp:BoundField>
<asp:BoundField HeaderText="PDM EntityID" DataField="PDM_ENTITY_ID" Visible="false"></asp:BoundField>
<asp:TemplateField HeaderText="Mapping Status" HeaderStyle-CssClass="width_120 aligned_center" ItemStyle-CssClass="width_120 aligned_center" Visible="true">
<ItemTemplate>
<asp:DropDownList id="ddlMappingStatus" runat="server" SelectedValue='<%# Bind("MappingCompleted") %>' OnSelectedIndexChanged="ddlMappingStatus_SelectedIndexChanged" AutoPostBack="true">
<asp:ListItem Text="Done" Value="DONE"></asp:ListItem>
<asp:ListItem Text="Not Done" Value="NOT DONE"></asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And the code behind is:
protected void ddlMappingStatus_SelectedIndexChanged(object sender, EventArgs e)
{
int MappingID = Convert.ToInt16(grdMappingList.SelectedRow.Cells[0].Text);
DropDownList ddgvOpp = (DropDownList)grdMappingList.SelectedRow.FindControl("ddlMappingStatus");
if (ddgvOpp.Equals("DONE"))
{
}
}
I am getting an error on this line:
DropDownList ddgvOpp (DropDownList)grdMappingList.SelectedRow.FindControl("ddlMappingStatus");
and this line:
int MappingID = Convert.ToInt16(grdMappingList.SelectedRow.Cells[0].Text);
It seems that I can't retrieve the values! I dont know why. When I choose a new status from the DropDownList, I want to get all the values of the row in order to update the record.
Unfortunately, SelectedRow does not mean what you think it means. It doesn't just simply mean the current row you are working on or the current row with the controls that you are using. That property must get set somehow. This is usually done through a "Select" button on the GridView, such as an <asp:ButtonField> with the command name "Select".
You really do not need this however. You just need the row you are working with. Since you are using the SelectedIndexChanged event of your DropDownList, you already have what you need. You just need to go about it a different way.
First, get the DropDownList. Then get the row of the DropDownList. Now do whatever you need with the row.
But, from your code, it looks like you may not even need the row. You just need the value of the DropDownList. So you could skip that all together. But if you do need the row, here is how you would do that too.
protected void ddlMappingStatus_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddlMappingStatus = (DropDownList)sender;
if(ddlMappingStatus.SelectedItem.Text.ToUpper() == "DONE")
{
}
GridViewRow row = (GridViewRow)ddlMappingStatus.NamingContainer;
}
Now when you use <asp:BoundField> controls in your GridView, getting their values isn't very clean. You are forced to hardcode the column index like you were doing:
GridViewRow row = (GridViewRow)ddlMappingStatus.NamingContainer;
String mappingID = row.Cells[0].Text;
I tend to prefer using <asp:TemplateField> controls so I can use FindControl() to get what I am after. This prevents any reordering of the columns from breaking the code, as you'd have to hardcode different indexes. So for example, to find that DropDownList (since it already is a <asp:TemplateField>), you'd do something like this:
DropDownList ddlMappingStatus = (DropDownList)row.FindControl("ddlMappingStatus");
I have 4 columns in Telerik RadGrid
1) Account Code (only column shown in "Edit" and "Add" mode - Dropdown)
2) Account Description
3) Amount
4) Remark
Below is the "Add" mode code I am using:
HTML code:
<mastertableview ShowHeadersWhenNoRecords="true" autogeneratecolumns="false" datakeynames="AccountCodeID" InsertItemDisplay="Top"
insertitempageindexaction="ShowItemOnCurrentPage" ShowFooter="True" CommandItemDisplay="Top">
<Columns>
<telerik:GridEditCommandColumn></telerik:GridEditCommandColumn>
<telerik:GridTemplateColumn UniqueName="AccountCode" HeaderText="Account Code">
<ItemTemplate>
<asp:Label ID="lblAcCode" Text='<%# Eval("AccountCode") %>' runat="server"></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlAcCode" DataTextField="AccountDescription" DataValueField="AccountCodeID" runat="server"/>
</EditItemTemplate>
</telerik:GridTemplateColumn>
<telerik:GridBoundColumn DataField="AccountDescription" HeaderText="Description" UniqueName="AccountDescription" SortExpression="AccountDescription" InsertVisiblityMode="AlwaysHidden" ReadOnly="true" ></telerik:GridBoundColumn>
<telerik:GridBoundColumn aggregate="SUM" DataField="Amount" HeaderText="Amount" FooterText="Total : " UniqueName="Amount" SortExpression="Amount"></telerik:GridBoundColumn>
<telerik:GridBoundColumn DataField="Remark" HeaderText="IFCA Remark" UniqueName="Remark" SortExpression="Remark">
</telerik:GridBoundColumn>
<telerik:GridButtonColumn CommandName="Delete" Text="Delete" UniqueName="DeleteColumn"></telerik:GridButtonColumn>
</Columns>
<EditFormSettings>
<EditColumn ButtonType="ImageButton" />
</EditFormSettings>
<CommandItemSettings AddNewRecordText="Add new record" RefreshText="Refresh"></CommandItemSettings>
</mastertableview>
C# code:
protected void RGGSTAcCode_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item is GridEditableItem && e.Item.IsInEditMode)
{
GridEditableItem item = e.Item as GridEditableItem;
string CompanyCode = ddlCompany.SelectedValue.ToString();
DropDownList list = item.FindControl("ddlAcCode") as DropDownList;
list.DataTextField = "AccountDescription";
list.DataValueField = "AccountCodeID";
list.DataSource = GetAccCode(CompanyCode);
list.DataBind();
list.Items.Insert(0, "- Select -");
}
}
protected void RGGSTAcCode_InsertCommand(object sender, GridCommandEventArgs e)
{
GridEditableItem item = e.Item as GridEditableItem;
DropDownList accountCode = item.FindControl("ddlAcCode") as DropDownList;
string SelectedAccCode = accountCode.SelectedItem.Text;
//split dropdown 2 vales
string accCode = SelectedAccCode.Substring(0, SelectedAccCode.IndexOf('-')).Trim(); //getting a/c code
string accDesc = SelectedAccCode.Substring(SelectedAccCode.IndexOf('-') + 1).Trim(); //getting a/c descr
InsertAccountCode(new Guid(TempGUID.Text), accCode, accDesc);
BindGrid();
RGGSTAcCode.Rebind();
}
"Account code" column is only shown in "Add" and "Edit" mode of RadGrid. It is a Dropdown in which I have to bind the 2 values together i.e., Account code + Account Description, and have to show and save it in separate columns of Database. (i.e, Account Code value in Account code column and Account Description value in Description column)
Now my requirement is that: While doing "Edit", I want to bind/display the "Account code" column data and "Account Description" column data together inside Dropdown, which is saved in Database for a particular ID. Just like we bind dropdown while Edit.
and later after Editing the Dropdown item, data will be saved to two different columns of DB as I am doing while Adding the records.
Only I am not getting how to display/bind the two different columns data together inside a Dropdown when doing "Edit".
Please suggest some solution.
I hope I am able to make my requirement clear.
Thanks in advance.
Hmm.. Clear your thoughts about this issue.
What type of databind you are using ? whether advanced databind / sqldatasource databind?
Anyway you have four columns in your grid right! so change your select query like below one.
SELECT accountcode, accountdesc, amount, remark, convert(varchar(20),accountcode)+' '+accountdesc as accdetail FROM YOURTABLENAME
<-- Note down that accdetails.
I'm concatanating the fields accountcode and accountdesc as accdetail (with a empty space ).
So now your grid has 5 rows. Hide the fifth row in the gridview using Visible="false" in that accdetail column.
Don't modify the accountcode column.
Do the change only in Dropdownlist.
<asp:DropDownList ID="ddlAccdetail" DataTextField="accdetail" DataValueField="accdetail" runat="server"/>
Now the dropdown will show the content as accountcode accountdesc in editmode.
On Insert, do the following code change
protected void RGGSTAcCode_InsertCommand(object sender, GridCommandEventArgs e)
{
GridEditableItem item = e.Item as GridEditableItem;
DropDownList ddlAccdetail = item.FindControl("ddlAccdetail") as DropDownList;
string Accdetail = ddlAccdetail.SelectedItem.Text;
string accCode=Accdetail.Split(' ')[0]; //Splitting the string
string accDesc=Accdetail.Split(' ')[1]; //with that added empty space
InsertAccountCode(new Guid(TempGUID.Text), accCode, accDesc);
BindGrid();
RGGSTAcCode.Rebind();
}
Thats it, hope it will work. But keep it in mind if you have any empty space in your accountcode or accountdesc field by default, then you need to change that Empty space to any special character like ( - , * , / ,)
in a datatable you can rename column as follows:
dt.Column[0].ColumnName="name";
Is it possible to do something similar with list<MyType>? I need to retrun list of objects with modified column names. to bind to a gridview some special way.
You can go with anonymous types:
var yourList = new List<MyType>{ ... };
var newList = yourList.Select( i=> new { NewColumn = i.OldName });
In the asp.net gridviews you can use Bound Fields to Bind Properties and Set the Column Headers to whatever you want
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" >
<Columns>
<asp:BoundField DataField="MyProperty" HeaderText="My Custom Column Heaer" />
</Columns>
</asp:GridView>
Just make sure the MyProperty exists on the MyType and you should be good.
On an ASP.NET page, I have a gridview which contains a dropdownlist in one of its columns. While other columns in the gridview are databound, the dropdown list is NOT, and only contains 3 preset values "Frank", "Yes", and "No". ("Frank" is used as an example so that I don't get false readings from my preferred blank option)
<asp:GridView ID="testGrid" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="Code1" HeaderText="Code1" />
<asp:BoundField DataField="Code2" HeaderText="Code2" />
<asp:TemplateField HeaderText="Like Frank?">
<ItemTemplate>
<asp:DropDownList runat="server" ID="ddlLikeFrank">
<asp:ListItem>Frank</asp:ListItem>
<asp:ListItem>Yes</asp:ListItem>
<asp:ListItem>No</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
<asp:HyperLinkField ... HeaderText="File" />
</Columns>
</asp:GridView>
<br />
<asp:Button ID="cmdUpdate" runat="server" Text="Update" OnClick="cmdUpdate_Click" /></div>
I don't need AutoPostBack on these dropdownlists, as I only want to consider their selected values when the button cmdUpdate is clicked.
protected void cmdUpdate_Click(object sender, EventArgs e)
{
bool likesFrank = false;
string selected = "";
DropDownList ddl = null;
GridViewRow current = null;
// Go through each row and check the dropdown list.
for (int i = 0; i < testGrid.Rows.Count; i++)
{
current = testGrid.Rows[i];
...
ddl = (DropDownList)(current.FindControl("ddlLikeFrank"));
/* THIS FOR LOOP IS WAS USED FOR INVESTIGATING THIS ISSUE*/
for (int j = 0; j < ddl.Items.Count; j++)
{
if (ddl.Items[j].Selected)
{
continue;
}
}
selected = ddl.SelectedItem.Value;
switch (selected)
{
case LIKE: // "Yes"
likesFrank = true;
break;
case DONT_LIKE: // "No"
likesFrank = false;
break;
default: // If nothing is selected in the drop-down list, move on.
continue;
} // end switch block
/* USE THE DERIVED BOOLS HERE */
} // end for loop on grid rows
} // end method cmdUpdateClick
The problem is this: No matter what item is selected in any of the dropdownlists, my page thinks that every single one of them is set to "Frank", i.e. the first item. Moreover, if I put a breakpoint on the top of the for loop denoted as the "Investigation code", and then interact with the page as follows:
Select different dropdownlist options for different rows.
Click the Update button.
... my debugging code tells me that none of the items are selected! Not one of them!! I can be looking at 2 Yes's and 3 No's on the page, and my debug tools in VS2008 are telling me that every single dropdownlist has nothing selected.
How can this be possible? (NOTE: I have tried this with EnableViewState set to true, and with EnableViewState not even mentioned in the page header.)
Thanks.
take a hit with this. Replace index based for with this
foreach(GridViewRow row in grid.Rows)
{
var ddlVal = ((DropDownList)row.FindControl("yourId")).SelectedItem.Value;
}
<< use SelectedItem.Value - I think this will solve your problem >>
Update:
To update the selected index of the ddl you needto do a postback. Enable autopostback=true. But here , you have mentioned you do not want autopostback, since this isthe only workaround, so place the gridview in an updatepanel to suppress postback
At server side
protected void btnSaveRankChanges_Click(object sender, EventArgs e)
{
foreach (GridViewRow grv in GridViewRankChanges.Rows)
{
DropDownList dropDownChangeRank = (DropDownList)grv.FindControl("DropDownListRank");
StudentInfoObject.RankID = Convert.ToInt32(dropDownChangeRank.SelectedValue);
}
}
in grid
<asp:TemplateField HeaderText="Select New Rank">
<ItemTemplate>
<asp:DropDownList ID="DropDownListRank" runat="server">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
On button click
<asp:Button ID="btnSaveRankChanges" runat="server" Text="Submit" ValidationGroup="RankChanges"
class="accordionHeader" Height="27px" OnClick="btnSaveRankChanges_Click" OnClientClick="LoadImage()" />
Dropdown binds in this way
/// <summary>
/// bind dropdown with rank in grid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void GridViewRankChanges_RowDataBound(object sender, GridViewRowEventArgs e)
{
DropDownList drdList;
// Nested DropDownList Control reference is passed to the DrdList object. This will allow you access the properties of dropdownlist placed inside the GridView Template column.
if (e.Row.RowType == DataControlRowType.DataRow)
{
//bind dropdown rank
drdList = (DropDownList)e.Row.FindControl("DropDownListRank");
drdList.DataSource = RankList.GetRankList(false);
drdList.DataTextField = "Rank";
drdList.DataValueField = "RankID";
drdList.DataBind();
drdList.Items.Insert(0, new ListItem("Select", "0"));
}
}
It works for me hope it helps for you too.
I think you are rebinding the grid on every post back, which will reload the entire data along with dropdowns. For ex. Please check if(!page.IsPostBack) before doing databiniding of gridview.
Please let me know if this is not the issue.