Hi I have a problem with my GridView.
Let's say that I create a GridView with 4 columns
|NAME|LASTNAME|OWNER|ADMINISTRATOR|
Owner and Administrator are columns that can contain a checkbox.
Second step: I fill the grid in some way.
Third step: I add dynamically the check box on the owner and admin columns, depending on some strange method.
Four step: When I click the Button below the gridview, the click event will read how many checkbox are checked and pass that number to another method.
This last step is quite difficult because all the checkboxes disappear, due to the postback of the button.
I looking for a method to save the checkboxes from the postback.
Can I call a method after the click, and before the postback?
Can I avoid the postback of a button?
(PS: I prefer to not go for js solution)
If you place the method call to dynamically add the check boxes in Page_Init they will not be removed on postback
It's not clear from your question why you need to have dynamically added CheckBox controls, when you can just set their state server-side in the RowDataBound event of the GridView. Here is a worked example of your requirment boiled down to the barest minimum to illustrate:
CheckboxGrid.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeFile="CheckboxGrid.aspx.cs" Inherits="CheckboxGrid" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="gvResourceUsers" runat="server" AutoGenerateColumns="False" OnRowDataBound="gvResourceUsers_OnRowDataBound">
<Columns>
<asp:BoundField HeaderText="Name" DataField="Name"/>
<asp:BoundField HeaderText="Surname" DataField="Surname"/>
<asp:TemplateField HeaderText="Owner">
<ItemTemplate>
<asp:CheckBox ID="cbxOwner" runat="server"/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Administrator">
<ItemTemplate>
<asp:CheckBox ID="cbxAdministrator" runat="server"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button runat="server" ID="btnSubmit" Text="Save" OnClick="btnSubmit_Click"/>
</div>
</form>
</body>
</html>
CheckboxGrid.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class CheckboxGrid : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//Get data and bind the grid
gvResourceUsers.DataSource = GetData();
gvResourceUsers.DataBind();
}
}
protected void gvResourceUsers_OnRowDataBound(Object sender, GridViewRowEventArgs e)
{
//As each row is data-bound, set the checkbox state.
if (e.Row.RowType == DataControlRowType.DataRow)
{
var resourceUser = e.Row.DataItem as ResourceUser;
var cbxOwner = e.Row.FindControl("cbxOwner") as CheckBox;
var cbxAdministrator = e.Row.FindControl("cbxAdministrator") as CheckBox;
cbxOwner.Checked = resourceUser.Owner;
cbxAdministrator.Checked = resourceUser.Administrator;
}
}
protected void btnSubmit_Click(Object sender, EventArgs e)
{
var resourceUsers = new List<ResourceUser>();
//Iterate the gridview rows and populate the collection from the postback data.
foreach (GridViewRow row in gvResourceUsers.Rows)
{
resourceUsers.Add(
new ResourceUser
{
Name = row.Cells[0].Text,
Surname = row.Cells[1].Text,
Owner = ((CheckBox)row.Cells[2].FindControl("cbxOwner")).Checked,
Administrator = ((CheckBox)row.Cells[3].FindControl("cbxAdministrator")).Checked
});
}
}
private IEnumerable<ResourceUser> GetData()
{
//We just create some data for demo purposes. Here you would normally populate the collection from your database.
var resourceUsers = new List<ResourceUser>
{
new ResourceUser{Name = "Bob", Surname = "Taylor", Owner = true, Administrator = true },
new ResourceUser{Name = "Ann", Surname = "Carter", Owner = false, Administrator = true },
new ResourceUser{Name = "Toni", Surname = "Wong", Owner = false, Administrator = false}
};
return resourceUsers;
}
//A data view model to contain our view data for the grid
private class ResourceUser
{
public String Name { get; set; }
public String Surname { get; set; }
public Boolean Owner { get; set; }
public Boolean Administrator { get; set; }
}
}
Related
I am using ASP.NET C#. I have a Gridview (example shown below) and a Button. As I click on the rows of the gridview, my button’s text needs to change depending on the info of the gridview.
For example: If I click on the first row, the text of my Button should be Alpha (Operation name). If I click on the third row, it should have Charlie on it and so on. The user could click any row any number of times.
I have learnt the use of onRowDataBound and SelectedIndexChanged event of the gridview to play around with the value in the gridview. I was able to print out each row of the gridview using labels. However I do not understand how I can change the text of a button using this method.
Any help in either Javascript/JQuery would be greatly appreciated. Please let me know if the question is unclear in anyway.
Using SelectedIndexChanged is possible to change button label based on selected row on gridview. Set AutoGenerateSelectButton as true and create an event OnSelectedIndexChanged.
public class MyModel
{
public int Id { get; set; }
public string Operation { get; set; }
public string Month { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
var data = new List<MyModel>()
{
new MyModel() { Id = 101, Operation = "Alpha", Month = "Jan" },
new MyModel() { Id = 102, Operation = "Beta", Month = "Feb" },
new MyModel() { Id = 103, Operation = "Charlie", Month = "Mar" }
};
myGridView.DataSource = data;
myGridView.DataBind();
}
protected void myGridView_SelectedIndexChanged(object sender, EventArgs e)
{
var data = myGridView.DataSource as List<MyModel>;
if (data == null) return;
myButton.Text = data[myGridView.SelectedIndex].Operation;
}
aspx:
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<asp:GridView ID="myGridView" runat="server" AutoGenerateSelectButton="true" AutoGenerateColumns="true" OnSelectedIndexChanged="myGridView_SelectedIndexChanged">
<SelectedRowStyle BackColor="Red" />
</asp:GridView>
<asp:Button ID="myButton" runat="server" Text="---" />
</asp:Content>
As an alternative you can use Javascript on the client side:
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<asp:GridView ID="myGridView" ClientIDMode="Static" runat="server" AutoGenerateColumns="true"></asp:GridView>
<asp:Button ID="myButton" runat="server" Text="---" ClientIDMode="Static" />
<script>
// Add event onclick on rows
document.querySelectorAll("#myGridView tbody tr").forEach(a => a.addEventListener("click", _ => {
document.querySelector("#myButton").value = a.children[1].innerText;
}));
</script>
</asp:Content>
I want to dipslay in a Gridview with radiobutton list the current date when I run the project. I don't know if the best way is to use JavaScript or C# (I'm using it on Code Behind) and how to do it. If is need to show some code, say it. The grid is filled with a sql statement. The image below shows how I want the grid. Thank you
Unfortunately, you cannot use RadioButton.GroupName Property in GridView.
Easiest way is to place RadioButton in TemplateField, and use jQuery to manipulate it.
ASPX
<asp:GridView runat="server" ID="GridView1">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:RadioButton runat="server" ID="MyRadioButton"
CssClass="myRadioButton"
onclick='<%# "myRadioButtonClick(this)" %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
function myRadioButtonClick(sender) {
$('.myRadioButton input').attr('checked', false);
$(sender).attr('checked', true);
}
</script>
Code Behind
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
GridView1.DataSource = new List<Customer>
{
new Customer {Id = 1, Name = "John"},
new Customer {Id = 2, Name = "Marry"},
};
GridView1.DataBind();
}
<ItemTemplate>
<tr>
<asp:LinkButton ID="btnID" runat="server"
ToolTip='The calculated IDs are: ' OnCommand="showIds"
CommandArgument='<%# Convert.ToInt32(Eval("Year")) + "," +
Convert.ToInt32(Eval("Month")) %>'>
<%# Convert.ToInt32(Eval("Count")) - Convert.ToInt32(Eval("LittleCount"))%>
</asp:LinkButton>
</tr>
</ItemTemplate>
As you can notice the tooltip text is static. In code behind, I do calculate and get some integers ( IDs ) every time the above button is clicked ( protected void showIds(object sender, CommandEventArgs e) { .... }) contained as a List<ExpressionListDictionary>. ( the asp:LinkButton is contained inside an asp:ListView )
What I want to do, is to change the tooltip into a dynamic one, containing all the already obtained IDs as links. ( Something like this: http://jsfiddle.net/IrvinDominin/jLkcs/5/ - but in my case I do need firstly to click the button for calculating the IDs, and after this I would need to change the tooltip text from code as it needs to show the respective IDs, as links if it is possible)
How can I achieve this?
If you have a class (or id or something) to identify the buttons you can make an jQuery document ready function to change the tooltip with ids to a link containing the ids.
I modifyed your fiddle: http://jsfiddle.net/jLkcs/545/
$(document).ready(function () {
$(".myLinkButton").each(function() {
createlink(this);
});
});
function createlink(obj){
var ids= $(obj).attr('title');
var linkHtml="<a href='javascript:alert(" + ids + ")'>link</a>"
$(obj).attr('title',linkHtml);
}
Why not simply adjust the ToolTip in the codebehind during postback?
protected void showIds(object sender, CommandEventArgs e)
{
((LinkButton)sender).ToolTip = "blahblah";
}
You can set your sender attributes if the CommandEventArgs CommandName is equal with your defined one
public void LinkButton_Command(Object sender, CommandEventArgs e)
{
if (e.CommandName.Equals("showIds"))
{
//
}
}
Here is an working example, this will work, not counting in what user control LinkButton is used:
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : Page
{
public string btnNoTooltip = "No IDs are calculated";
public string btnTooltip = "The calculated IDs are:";
protected void Page_Load(object sender, EventArgs e)
{
}
public void LinkButton_Command(Object sender, CommandEventArgs e)
{
if (e.CommandName.Equals("LinkButtonOrder"))
{
LinkButton lkTrigger = (LinkButton)sender;
if (lkTrigger.ToolTip.Equals(btnNoTooltip))
{
lkTrigger.ToolTip = btnTooltip + " " + e.CommandArgument;
}
else
{
lkTrigger.ToolTip += " " + e.CommandArgument;
}
Random random = new Random();
lkTrigger.CommandArgument = random.Next(0, 100).ToString();
Label1.Text = "Triggered: " + e.CommandName + " with Argument " + e.CommandArgument;
}
}
}
Markup:
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<h3>LinkButton Command Event Example</h3>
<asp:LinkButton id="LinkButton1"
Text="Order Item Here"
CommandName="LinkButtonOrder"
ToolTip='No IDs are calculated'
CommandArgument="01"
OnCommand="LinkButton_Command"
runat="server"/>
<br />
<asp:LinkButton id="LinkButton2"
Text="Or Order Item Here"
CommandName="LinkButtonOrder"
CommandArgument="02"
ToolTip='No IDs are calculated'
OnCommand="LinkButton_Command"
Runat="server"/>
<br />
<br />
<asp:Label id="Label1" runat="server"/>
<asp:PlaceHolder id="plhInjectId" runat="server" Visible="false"></asp:PlaceHolder>
</asp:Content>
You can use jquery to generate Tool Tip on Page itself.
Add a hidden field for your all the already obtained IDs (comma sepearted) to asp:ListView
Populate this hidden in ItemCreated event on server
add a class to your link button, say 'ShowHyperlinkOnHover'
Bind mouseenter event to class ShowHyperlinkOnHover document.ready function of jquery, this will dynamically generate tool tip. and then on Mouse Over tool tip will be displayed.
$(document).ready(function () {
$(document).on("mouseenter", ".ShowHyperlinkOnHover", function(this){
// 2 is index of hidden field having comma seperated Ids
var dynaToolTip;
$(this).parent("td:nth-child(2)").split(',').each(
function(oneId) dynaToolTip=dynaToolTip+ anyFomationLogic(oneId);
);
$(this).attr('title',dynaToolTip);
});
});
It has been so long since I've used Web Forms I find myself not remembering most of the perks.
I have a user control that has a button, a repeater and the ItemTemplate property of the repeater is another user control.
<asp:Button runat="server" ID="btnAdd" CssClass="btn" Text="Add" OnClick="btnAdd_Click"/>
<br/>
<asp:Repeater runat="server" ID="rptrRequests">
<ItemTemplate>
<uc1:ucRequest ID="ucNewRequest" runat="server" />
</ItemTemplate>
</asp:Repeater>
The idea is that when the user clicks on the Add button a new instance of the ucRequest is added to the collection. The code behind is as follows:
public partial class ucRequests : UserControl
{
public List<ucRequest> requests
{
get
{
return (from RepeaterItem item in rptrRequests.Items
select (ucRequest) (item.Controls[1])
).ToList();
}
set
{
rptrRequests.DataSource = value;
rptrRequests.DataBind();
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack) return;
requests = new List<ucRequest>();
}
protected void btnAdd_Click(object sender, EventArgs e)
{
var reqs = requests;
reqs.Add(new ucRequest());
requests = reqs;
}
}
After much googling I now remember that I should be binding the Repeater in the OnInit method in order for the ViewState to put the captured data of the controls within the ucRequest control on them between post backs but when I try to do that I will always have a single instance of the control on the Repeater since its Items collection is always empty.
How could I manage to do this?
Thanks in advance.
You just need control ids in view state stead of entire control collection.
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="ucRequests.ascx.cs"
Inherits="RepeaterWebApplication.ucRequests" %>
<asp:Button runat="server" ID="btnAdd" CssClass="btn" Text="Add"
OnClick="btnAdd_Click" />
<br /><asp:PlaceHolder runat="server" ID="PlaceHolder1"></asp:PlaceHolder>
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="ucRequest.ascx.cs"
Inherits="RepeaterWebApplication.ucRequest" %>
<asp:TextBox runat="server" ID="TextBox1"></asp:TextBox>
private List<int> _controlIds;
private List<int> ControlIds
{
get
{
if (_controlIds == null)
{
if (ViewState["ControlIds"] != null)
_controlIds = (List<int>) ViewState["ControlIds"];
else
_controlIds = new List<int>();
}
return _controlIds;
}
set { ViewState["ControlIds"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
foreach (int id in ControlIds)
{
Control ctrl = Page.LoadControl("ucRequest.ascx");
ctrl.ID = id.ToString();
PlaceHolder1.Controls.Add(ctrl);
}
}
}
protected void btnAdd_Click(object sender, EventArgs e)
{
var reqs = ControlIds;
int id = ControlIds.Count + 1;
reqs.Add(id);
ControlIds = reqs;
Control ctrl = Page.LoadControl("ucRequest.ascx");
ctrl.ID = id.ToString();
PlaceHolder1.Controls.Add(ctrl);
}
Try to get the ucRequests during the OnItemDatabound event, at that point you can edit the content of itemtemplate of the repeater. You can get there after the postback caused by the click on the add button. Here's a sample with a similar scenario
I have an ASP:Repeater Which I would like to display a list of check boxes in. These check boxes are related to a list of user preferences and the users resulting answer. See Code Bellow.
I would like to add do one of the following if possible
Option 1: It would be great if I could use the Event in the Repeater:OnItemCommand(...) to fire if any of the items change. It would seem to me that this event will only fire if there is a Button | LinkButton | ImageButton item in the list. IE it will not fire if I put in a check box with AutopostBack="True"
Option 2: Is there a way I could attach a method to an Event of CheckBox:CheckChanged I would need to pass this method a parameter saying which question/answer combo to change.
Option 3: Its your answer if you know an easier way that would be awesome.
The Code:
<asp:Repeater ID="RPTprefs" runat="server" DataSourceID="getAnswers" OnItemCommand="RPTprefs_ItemCommand">
<ItemTemplate>
<li><asp:CheckBox ID='questionID' runat="server"
Checked='<%# Eval("pr.up_is_selected") %>'
Text='<%# Eval("prp.prefs_question") %>'
AutoPostBack="true"
OnCheckedChanged="CheckChanged" /></li>
</ItemTemplate>
</asp:Repeater>
Thanks in advance
Here is what I came up with, which is basically your option #2.
In the ItemTemplate of the repeater, I use a Literal control (Visible set to false) which has the argument you wish to pass to the CheckedChanged function. The reason for using a control is because the control will retain its value in the ViewState after a post back, whereas the original data source for the Repeater will be lost.
In the OnItemCreated function, I bind the CheckChanged function for all of the check boxes to pass in the right argument. Here's my complete example. In this case, I want to pass the Id property of my data to the CheckChanged function.
Markup:
<asp:Repeater ID="Repeater1" runat="server" OnItemCreated="ItemCreated">
<ItemTemplate>
<asp:Literal ID="litArg" runat="server" Visible="false" Text='<%# Eval("Id") %>'>
</asp:Literal><%# Eval("Name") %>
<asp:CheckBox ID="chkCool" runat="server" AutoPostBack="true" Checked='<%# Eval("IsCool") %>' /><br />
</ItemTemplate>
</asp:Repeater>
Code behind:
public class SomeClass
{
public SomeClass(bool c, string n, int id)
{
IsCool = c;
Name = n;
Id = id;
}
public bool IsCool { get; set; }
public string Name { get; set; }
public int Id { get; set; }
}
.
.
.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<SomeClass> people = new List<SomeClass>();
people.Add(new SomeClass(true, "Will", 666));
people.Add(new SomeClass(true, "Dan", 2));
people.Add(new SomeClass(true, "Lea", 4));
people.Add(new SomeClass(false, "Someone", 123));
Repeater1.DataSource = people;
Repeater1.DataBind();
}
}
private void CheckChanged(int id)
{
Response.Write("CheckChanged called for item #" + id.ToString());
}
protected void ItemCreated(object sender, RepeaterItemEventArgs e)
{
//this needs to be set again on post back
CheckBox chk = (CheckBox)e.Item.FindControl("chkCool");
Literal arg = (Literal)e.Item.FindControl("litArg");
Action<object, EventArgs> handler = (s, args) => CheckChanged(Convert.ToInt32(arg.Text));
chk.CheckedChanged += new EventHandler(handler);
}
Hope that helps.