Gridview - Reference to a new column - c#

I have a gridview which takes in data from 3 tables.
And this gridview also have an additional column called "Role" which is not included in the database.
Currently, without adding any logic but simply using the findcontrol to the label, "Role", i can show out "ML"
But, when I add in the logic, it did not appear at all.
In any case, does anyone knows how to insert "ML" into the "Role" column which is not found in the database but is reference from another column found in the database.
This is the codes used to display the "ML" in the role column.
protected void gridAMDisplay_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//find the Label control using FindControl and set its Text on some column value
DataRowView row = (DataRowView)e.Row.DataItem;
if (!DBNull.Value.Equals(row["ModuleLeader"]))
{
if (row["ModuleLeader"].ToString() == "ModuleStr")
{
Label lbl = e.Row.FindControl("lblRole") as Label;
if (lbl != null)
{
lbl.Text = "ML";
}
}
}
}
}
This part of the code when comment off, the ML can be displayed in the role column, otherwise, nothing is displayed.
Therefore, i feel that the findcontrol part works. BUT, referencing does not works.
if (row["ModuleLeader"].ToString() == "ModuleStr")
{
As i mentioned, the role column was not included in any of the tables in the DB.
Therefore, i added in this codes.
<asp:TemplateField HeaderText="Role">
<ItemTemplate>
<asp:Label ID="lblRole" runat="server" Text="" />
</ItemTemplate>
</asp:TemplateField>
But, the problem i have now is, the role column does not reference to the column it is supposed to, which is "Module Leaders"

You reference the DataItem, which cannot be used in DataBound, you should use OnDataBinding to implement this.

It seems you only want the role column to update to "ML" based on the data present in another column of the same row. Why not just drop it in the XHTML?
<asp:TemplateField HeaderText="Role">
<ItemTemplate>
<asp:Label ID="lblRole" runat="server" Text='<%# GetRoleString(Eval("ModuleLeader"))%>' />
</ItemTemplate>
</asp:TemplateField>
Then in the code behind you could have a method:
string GetRoleString(string moduleLeader)
{
return (moduleLeader == "ModuleStr") ? "ML" : "";
}
This would occur on databinding and would only happen once per row.

The best practice in my humble opinion is to create your own template.
Here is one for your case :
public class NotEmptyValueFromDataTemplate : System.Web.UI.Page, IBindableTemplate
{
protected string p_DataFieldToLookAt;
protected string p_ValueToPlaceInIfNotNull;
protected Literal p_litControl;
public RoleTemplate(string DataFieldToLookAt, string ValueToPlaceInIfNotNull)
{
this.p_DataFieldToLookAt = DataFieldToLookAt;
this.p_ValueToPlaceInIfNotNull = ValueToPlaceInIfNotNull;
}
public virtual void OnInit(object sender, EventArgs e)
{ }
#region IBindableTemplate Members
public System.Collections.Specialized.IOrderedDictionary ExtractValues(Control container)
{
throw new NotImplementedException();
}
#endregion
#region ITemplate Members
public void InstantiateIn(Control container)
{
p_litControl = new Literal();
p_litControl.ID = p_DataFieldToLookAt; /* we don't really care */
p_litControl.Init += new EventHandler(OnInit);
p_litControl.DataBinding += new EventHandler(p_litControl_DataBinding);
container.Controls.Add(p_litControl);
}
void p_litControl_DataBinding(object sender, EventArgs e)
{
var Data = ((GridViewRow)(p_litControl.NamingContainer)).DataItem;
string ValueFromData = Convert.ToString(DataBinder.Eval(Data, p_DataFieldToLookAt));
if(!String.IsNullOrEmpty(ValueFromData))
p_litControl.Text = p_ValueToPlaceInIfNotNull;
}
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
}
#endregion
}
You have then to instantiate each template row :
protected void GridView3_Init(object sender, EventArgs e)
{
((TemplateField)(GridView3.Columns[/* Column Index Here*/])).ItemTemplate = new NotEmptyValueFromDataTemplate("ModuleLeader", "ML");
}
Last, create the template item in the gridview :
<asp:TemplateField HeaderText="Role"></asp:TemplateField>
PS : Code is untested and written out of solution

Related

asp.net: How to update data in GridView through Checkbox in particular row

I am developing a Web Form, where I show Gridview with data. One of the column consists of CheckBox. How can I update data in particular row.
so my question is:
How to unidentified particular row and send an sql request with UPDATE when user Check or Uncheck the CheckBox?
Update:
Here is my code that i have. It doesn't update value of CheckBox.
namespace:
public partial class Call_Bills : System.Web.UI.Page
{
SqlConnection con = new SqlConnection();
string check;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button_Submit(object sender, EventArgs e)
{
foreach (GridViewRow row in GridView2.Rows)
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["TestDeductionsConnectionString2"].ToString();
con.Open();
bool private1 = (row.FindControl("CheckBox1") as CheckBox).Checked;
if (private1 == true)
{
check = "1";
}
else
{
check = "0";
}
SqlCommand cmd = new SqlCommand("insert into DetailCosts(private) values(#private)", con);
cmd.Parameters.AddWithValue("#private", check);
cmd.ExecuteNonQuery();
}}
name of GridView is: GridView2;
name of Checkbox in the Table: private;
id of CheckBox in Gridview is:
<asp:TemplateField HeaderText="Private" SortExpression="private">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" Checked='<%# Eval("private") %>' />
</ItemTemplate>
<HeaderStyle HorizontalAlign="Center" />
</asp:TemplateField>
you can manually define a method to handle a postback generated by a control inside a gridview column. To do that you just need to add the tags AutoPostBack=True and OnCheckedChanged=YourMethodName to the control.
On the code-behind, define this method as public void, and define the parameters that usually would be there (sender as object and e as EventArgs), like:
public void YourMethodName(object sender, EventArgs e)
On the method, you may need to get the GridViewRow which contains the control that has generated the event. To do that, just parse the sender parameter (which will be the checkbox) and get 2 parent levels (GridViewCell and GridViewRow), it would be something like:
GridViewRow row = ((CheckBox)sender).parent.parent;
Since you have the row, you may get any control inside it with the FindControl method. If you need an id to identify the entitiy being updated, you may store it in a hidden field inside the row.
Hope it helps!

How to save option selected in Dropdownlist after selection

I am displaying columns in a GridView and one of the columns is a dropdownlist. I want to be able to save the option selected in the dropdownlist as soon as something is selected. I have done this with one of the columns that has a textbox so I was hoping to do something similar with the DropDownList.
The code for the textbox and dropdownlist:
protected void gvPieceDetails_ItemDataBound(object sender, GridViewRowEventArgs e) {
if (e.Row.RowType == DataControlRowType.DataRow) {
JobPieceSerialNo SerNo = e.Row.DataItem as JobPieceSerialNo;
if (SerNo != null) {
TextBox txtComment = e.Row.FindControl("txtComment") as TextBox;
txtComment.Text = SerNo.Comment;
txtComment.Attributes.Add("onblur", "UpdateSerialComment(" + SerNo.ID.ToString() + ", this.value);");
DropDownList ddlReasons = (e.Row.FindControl("ddlReasons") as DropDownList);
DataSet dsReasons = DataUtils.GetUnapprovedReasons(Company.Current.CompanyID, "", true, "DBRIEF");
ddlReasons.DataSource = dsReasons;
ddlReasons.DataTextField = "Description";
ddlReasons.DataValueField = "Description";
ddlReasons.DataBind();
ddlReasons.Items.Insert(0, new ListItem("Reason"));
}
}
How to I create an update function for a dropdownlist?
protected void DDLReasons_SelectedIndexChanged(object sender, EventArgs e)
{
string sel = ddlReasons.SelectedValue.ToString();
}
public static void UpdateSerialReason(int SerNoID, string Reasons)
{
JobPieceSerialNo SerNo = new JobPieceSerialNo(SerNoID);
SerNo.Reason = sel; //can't find sel value
SerNo.Update();
}
Dropdownlist:
<asp:DropDownList ID="ddlReasons" runat="server" OnSelectedIndexChanged="DDLReasons_SelectedIndexChanged" AutoPostBack="true"></asp:DropDownList>
I created an OnSelectedIndexChanged function to get the selected value. But how do I then save that value? Is there a way to pass it into the UpdateSerialReason function?
Just move the string sel declaration outside the scope of DDLReasons_SelectedIndexChanged and get the Text of the SelectedItem since it's included in your data source.
private string sel;
protected void DDLReasons_SelectedIndexChanged(object sender, EventArgs e)
{
sel = ddlReasons.SelectedItem.Text;
}
public static void UpdateSerialReason(int SerNoID, string Reasons)
{
JobPieceSerialNo SerNo = new JobPieceSerialNo(SerNoID);
SerNo.Reason = sel; // Should now be available
SerNo.Update();
}
The way you had it previously it was only available in the local scope, i.e, inside the method in which it was being declared and used.
You can get selected value when you call your function:
UpdateSerialReason(/*Some SerNoID*/ 123456, ddlReasons.SelectedValue)
You will lose your value after postback is done if you save value to variable as Equalsk suggested. If you need to use your value on the other page you can save it in session.
If you are working within one asp.net page you can do as I suggested above. Then you can skip the postback on your DropDownList and call UpdateSerialReason when you need :)
And you might want to add property ViewStateMode="Enabled" and EnableViewState="true"

Find and change a specific item in Repeater

I have the following <asp:Repeater>:
<asp:Repeater ID="repMenuParent" runat="server" DataSourceID="odsMenuParent" OnItemCommand="repMenuParent_OnItemCommand" OnItemDataBound="repMenuParent_OnItemDataBound" >
<ItemTemplate>
<asp:Button id="btnRepeaterParent" runat="server" SkinID="btnAgroquimicos" CssClass="celdasMenusDinamicas" Text='<%# Eval("NOMBRE") %>' CommandName='<%# Eval("NOMBRE") %>' />
</ItemTemplate>
</asp:Repeater>
When the commandEvent is triggered i set up a session with the commandName and the uniqueId:
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
Session.Add("nombreSubMenuAgro", e.CommandName);
String id = e.Item.UniqueID;
Session.Add("souceId", id);
}
The issue is the following: I need change the forecolor of the botton inside the repeater that is cicked by the user. In the beginnig all the buttons (items in the repeater) are gray. When someone is clicked I need to change the forecolor of it to red (like a bread crumb).
I've trying to find the item in the itemDataBound and compare the uniqueId but it doesn't work, i don't know how to find the specific item that is clicked to change the forecolor:
protected void repMenuParent_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
String sessionID = "";
Button btnRepeater;
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
btnRepeater = (Button)e.Item.FindControl("btnRepeaterParent");
if (btnRepeater != null)
{
if(btnRepeater.UniqueID.Equals(sessionID))
{
btnRepeater.ForeColor = System.Drawing.Color.FromArgb(69, 187, 32);
}
}
}
}
I've read many blog's threads about repeater and find it's items, but can´t find any that solved my issue, Can help me please?
I think this problem is best solved with Javascript though I do have a server side solution for you.
The command event object has a property called CommandSource. This gives you access to the button that triggered the command event.
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
Button btnRepeater=e.CommandSource;
btnRepeater.ForeColor = Drawing.Color.Red;
}
If you maintain a List of the IDs of the buttons pressed, then you can do the following:
First, change your button in the repeater to use CommandArgument not CommandName. Like so:
<asp:Button id="btnRepeaterParent" ... CommandArgument='<%# Eval("NOMBRE") %>' />
Create a page level property for accessing the list of IDs. Like so:
public List<string> ClickedIds
{
get
{
if(Session("ClickedIds") == null)
Session("ClickedIds") = new List<string>();
return (List<string>)Session("ClickedIds");
}
}
When one of your buttons in your repeater is clicked, handle it like so:
protected void repMenuParent_OnItemCommand(object source, RepeaterCommandEventArgs e)
{
this.ClickedIds.Add(e.CommandArgument);
}
Now, when you are binding the repeater in code-behind, check each button like so:
protected void repMenuParent_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
//retrieve the id of the data item
//I am not sure of your data item structure, but it will be something to this effect
int nombre = e.Item.DataItem("NOMBRE");
if(this.ClickedIds.Contains(nombre))
{
((Button)e.Item.FindControl("btnRepeaterParent")).ForeColor = System.Drawing.Color.FromArgb(69, 187, 32);
}
}
}
DISCLAIMER:
I have not tested this code.

Show dropdown selected value in the grid on the same page

I have a drop down which has the list of delegates. When the user selects a delegate then I populate the available meet-timings in the second dropdown using the selectedindexchange event of the 1st dropdown
Aspx page
<asp:DropDownList ID="delegate_ddl" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ddldelegates_SelectedIndexChanged" Width="200px"></asp:DropDownList>
<asp:DropDownList ID="delegatetime_ddl" runat="server" Width="90px"></asp:DropDownList>
<asp:Button ID="adddelegate" runat="server" Text="Add" onclick="adddelegate_Click"/>
.cs page
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataSet ds1 = getdata.getdelegatelist();
delegate_ddl.DataSource = ds1.Tables[0];
delegate_ddl.DataTextField = "DELEGATE_NAME";
delegate_ddl.DataValueField = "DELEGATE_ID";
delegate_ddl.DataBind();
delegate_ddl.Items.Insert(0, "--Select--");
}
}
protected void ddldelegates_SelectedIndexChanged(object sender, EventArgs e)
{
string delselection = delegate_ddl.SelectedValue.ToString();
DataSet ds2 = getdata.getdelegatetimelist(delselection);
if (ds2.Tables[0].Rows.Count > 0)
{
delegatetime_ddl.DataSource = ds2.Tables[0];
delegatetime_ddl.DataTextField = "TIMESLOT";
delegatetime_ddl.DataValueField = "TIMEID";
delegatetime_ddl.DataBind();
}
else
{
time_lbl.Text = "No slots Open";
}
}
protected void adddelegate_Click(object sender, EventArgs e)
{
string delegateselected = delegate_ddl.SelectedValue.ToString();
string timeslotselected = delegatetime_ddl.SelectedValue.ToString();
getdata.delegatemeetinsert(personidd, delegateselected, timeslotselected);
}
Now the data gets inserted – but my question here is
As soon as the user click add button I would like to display the delegate selected and the time slot selected in a some sort of a grid view or dynamic table below with a delete option.
Can someone please provide a code sample in C# to achieve the above
Instead of using Gridview for displaying data use some basic control like Labels,it will reduce lot's of unncessary code. use Asp.net 'Panel' control and encapsulate all label and button(for delete purpose) into Panel then hide/show according to need. here is the outline of code that might help you,
if(!page.IsPostBack) // This goes into Page_Load
{
Panel1.Visible=false;
}
protected void adddelegate_Click(object sender, EventArgs e) // add this additional code
{
Panel.Visible=True;
GetDelegate()// This method retrieve the delegate you inserted..
Lable1.Text= "Set here Delegate name you just Retrieved"
Label2.Text="Delegate time you retrived"
}
protected void BtnRemovedelegate_Click(object sender, EventArgs e)
{
string Personidd= retrieve person id
string delegateName= Lable1.text;
String timeslot=Label2.Text
SomeDeleteMethod(personidd, delegateName, timeslot);
Panel1.Visible=false;
}
Hope you get the idea..

asp .net How to hide a TemplateField of a gridview column but still access its value

I have a datagridview which is loaded through a strored procedure. It has an ID column which i want to hide it but still access its value. I set the dataKeyNames and i have a method
protected void grdTime_OnDataBound(object sender,EventArgs e)
{
grdTime.Columns[1].Visible = false;
}
which i am trying to hide this column but i get the following error. If i remove the line inside the method it works. Here is the error.
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
Try this code in the method and then check..
grdTime.Columns[0].Visible = false;
hide the column in Row_Created event
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Cells[1].CssClass = "hiddencol";
//e.Row.Cells[2].CssClass = "hiddencol";
}
else if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells[1].CssClass = "hiddencol";
//e.Row.Cells[2].CssClass = "hiddencol";
}
}
here hiddencol is a css class
.hiddencol
{
display:none;
}
in the above code i'm hiding second column of my grid
If you've set GridView's AutoGenerateColumns to true(default), the Columns-Collection is empty. Following should work then:
1.)
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
e.Row.Cells[0].Visible = false;
}
2.)
foreach (TableRow row in GridView1.Controls[0].Controls)
{
row.Cells[0].Visible = false;
}
you can use like this in gridview tag on .aspx page
<Columns>
<asp:BoundField HeaderText="Merchandise Id" DataField="MerchandiseId" Visible="false" /></columns>

Categories

Resources