I have an ASPxGridView that contains a column with a DataItemTemplate that contains an ASPxCheckBox. I then have a button outside of the grid that performs some actions based on whether the checkbox is checked.
The grid is defined as:
<dx:ASPxGridView ID="grid" runat="server">
<Columns>
<dx:GridViewDataColumn>
<DataItemTemplate>
<ds:ASPxCheckBox ID="checkbox" runat="server" />
</DataItemTemplate>
</dx:GridViewDataColumn>
<Columns>
</dx:ASPxGridView>
The grid is populated in Page_Load as such:
protected void Page_Load(object sender, EventArgs e)
{
//Some stuff
grid.DataSource = sourceTable;
grid.DataBind();
//Other stuff
}
Where sourceTable is defined as:
public DataTable sourceTable
{
get
{
if (ViewState["sourceTable"] == null)
return new DataTable();
return (DataTable)ViewState["sourceTable"];
}
set
{
ViewState["sourceTable"] = value;
}
}
And populated elsewhere. (The population is not important and works)
The code is implemented as such to ensure that sorting and paging works correctly on the grid, as defined in various DevExpress support topics. This is understandable. However, when we try to get the Checked value from checkbox on the button click, it is always false:
protected void button_Click(object sender, EventArgs e)
{
//Some stuff
for(int i = 0; i < grid.VisibleRowCount; i++)
{
//Other stuff
ASPxCheckBox checkbox = grid.FindRowCellTemplateControl(i, grid.Columns[0], "checkbox") as ASPxCheckBox;
if(checkbox.Checked) //Always false
{
//Do conditional stuff
}
//More stuff
}
//Even more stuff
}
I understand why this is always false as the grid rebinds the data and recreates the checkbox to its default state, any documentation I have found for this issue regarding DevExpress states to wrap the data binding in Page_Load in if(!Page.IsPostBack) which does indeed work, but breaks sorting and paging.
I'm sure I have the solution for this in other projects I have done, I just can't find it. What should be done in this case?
Note: I have shortened the code to as little as I can possibly get away with and have not tested it. There may be some small errors with the actual code, but use it as a guide to what I am trying to do and will clarify any issues people may come across.
EDIT: Using if(!Page.IsPostBack) or if(!Page.IsCallback) in Page_Load stops sorting and paging on the grid, removing this condition means Checked is always false. I need both sorting/paging to occur AND to be able to read the Checked value of the ASPxCheckBox in the DataItemTemplate.
Edited answer
It appears that when using editors in DataItemTemplate you have to use LoadPostData() to get their values.
Use:
for(int i = 0; i < grid.VisibleRowCount; i++)
{
ASPxCheckBox checkbox = grid.FindRowCellTemplateControl(i, grid.Columns[0], "checkbox") as ASPxCheckBox;
((IPostBackDataHandler)checkbox).LoadPostData(checkbox.UniqueID, Request.Form);
if(checkbox.Checked)
{
//Do conditional stuff
}
}
As for populating the grid, you can keep it inside the Page_Load without !IsPostBack because it does not affect the editors (and it will keep the filtering/sorting)
It can cause problems in other cases but this is not the case here.
Hope it helps! Please tell me if you have any questions
Because when you button click then page post to server and when page posting to server all control set to default value (If you don`t control isPostBack property). you grid control sorting doing in client side. but posting to server side and rendering to client side you sorting removed. You can use Callback.
Ex:
<dx:ASPxGridView ID="grid" runat="server" ClientInstanceName="grid" OnCustomCallback="ASPxGridView1_CustomCallback">
<Columns>
<dx:GridViewDataColumn>
<DataItemTemplate>
<dx:ASPxCheckBox ID="checkbox" runat="server" />
</DataItemTemplate>
</dx:GridViewDataColumn>
</Columns>
</dx:ASPxGridView>
<dx:ASPxButton ID="btnSend" runat="server" AutoPostBack="False" Text="Send" Width="100px" ClientInstanceName="btnSend">
<ClientSideEvents Click="function(s, e) { grid.PerformCallback(); }" />
</dx:ASPxButton>
Code behind:
if (!IsPostBack)
{
//Some stuff
grid.DataSource = sourceTable;
grid.DataBind();
//Other stuff
}
protected void ASPxGridView1_CustomCallback(object sender, DevExpress.Web.ASPxGridViewCustomCallbackEventArgs e)
{
for (int i = 0; i < grid.VisibleRowCount; i++)
{
//Other stuff
ASPxCheckBox checkbox = grid.FindRowCellTemplateControl(i, grid.DataColumns[0], "checkbox") as ASPxCheckBox;
if (checkbox.Checked) //Always false
{
//Do conditional stuff
}
//More stuff
}
}
show difference between callback and postback in c#
Difference between a Postback and a Callback
There are some variants.
Page_Init event handler
You can try to move your binding code to Page_Init event handler.
protected void Page_Init(object sender, EventArgs e)
{
grid.DataSource = sourceTable;
grid.DataBind();
}
PostData of CheckBox editor is loaded between Page_Init and Page_Load, so the values in your CheckBox column are going to be erased in Page_Load event after calling to grid.DataBind method.
GridViewCommandColumn with ShowSelectCheckbox="true"
Here is another possibility. You can imitate the desired behavior by using GridViewCommandColumn with ShowSelectCheckbox property.
<dx:GridViewCommandColumn ShowSelectCheckbox="true" />
You can use grid.Selection.IsRowSelected method to get the checked rows .
Here is example:
protected void Button1_Click(object sender, EventArgs e)
{
//Some stuff
for (int i = 0; i < grid.VisibleRowCount; i++)
{
//Other stuff
if (grid.Selection.IsRowSelected(i))
{
//Do conditional stuff
}
//More stuff
}
//Even more stuff
}
Related
BillingEntity = (string)rdr["BillingEntity"];
string[] split = BillingEntity.Split(',');
for (int i = 0; i < split.Length; i++)
{
split[i] = split[i].Trim();
if (split[i] == "Clinic")
{
BillingEntityCheckBox.Items[i].Checked = true;
Session["billingEntitySessionVar"] = Session["billingEntitySessionVar"]
+ " Clinic";
}
How can I check an item in a checkbox list from the underlying code?
I know with a single checkbox you use checkbox.checked = true. I had that working fine in my code, but I need to link the checkboxes together in a control so that I can trigger an event based on whether any of them has been changed by the user.
To give a little background, I'm pulling in data from a SQL database and outputting to the user interface through a WebForm.
I think you're missing the concept of databinding, is this what you're looking for?:
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
string[] myStrings = new string[] { "Example Value", "Not a Thing", "Many Things", "All the Thing" };
cblThingy.DataSource = myStrings;
cblThingy.DataBind();
}
protected void btnPushMe_Click(object sender, EventArgs e)
{
//for all the things
foreach(ListItem itemThing in cblThingy.Items)
{
//set a default of not selected
itemThing.Selected = false;
//if the text is the same
//you can have any check you like here
if (itemThing.Text == txtThing.Text)
//say that it's selected
itemThing.Selected = true;
}
}
}
^The "code behind"
<asp:Label ID="lblThing" runat="server" Text="If you type the text and push the button the thing with select." />
<asp:TextBox ID="txtThing" runat="server" Text="Example Value" />
<asp:Button ID="btnPushMe" runat="server" Text="Push My Button" OnClick="btnPushMe_Click" />
<asp:CheckBoxList ID="cblThingy" runat="server" />
^The webform xml
Hopefully that helps!
p.s. I think it would be a good idea to make a readonly property on the BillingEntity type, which would return a bool which does the check for "clinic" inside that class, making it more object oriented..
I am trying to find a way to page through a gridview table by year. In my database I have a "season" field and I want all of the data from 2014 shown on one page, all the data from 2013 on another, etc. This would also require different numbers of rows based on the year.
Here is how I would do it. I wouldn't use the default paging of the gridview to handle this. Instead, I would buttons (or linkbuttons) to imitate the paging so that you control the paging. This way, you will be able to handle the change in year as well as control what is displayed.
The Steps are as follows:
1) Add your gridview to the page with a big page size just to display everything
<asp:GridView ID="dgvRequests" runat="server" AutoGenerateColumns="False" PageSize="9999"> </asp:GridView>
2) Bind the Per Year data to it in the code behind since you are display everthing per year in your page load. As well as store a variable to track the year
public int CurrentYear
{
get {
if(ViewState["currentYear"] != null)
return (int)ViewState["currentYear"];
return 2014; //Default
}
set {
_ViewState["currentYear"]= value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dgvRequests.DataSource = GetYearData(CurrentYear); //Or Your variable
dgvRequests.DataBind();
}
}
3) Make controls to control the page. I used Link Buttons
<asp:LinkButton ID="lbtnPrevious" runat="server" OnClick="lbtnPrevious_Click"></asp:LinkButton>
<asp:LinkButton ID="lbtnlNext" runat="server" OnClick="lbtnlNext_Click"></asp:LinkButton>
4) On the click event, control the paging of the gridviews via the click event
protected void lbtnlNext_Click(object sender, EventArgs e)
{
dgvRequests.DataSource = GetYearData(++CurrentYear); //Or Your variable
dgvRequests.DataBind();
}
protected void lbtnPrevious_Click(object sender, EventArgs e)
{
dgvRequests.DataSource = GetYearData(--CurrentYear); //Or Your variable
dgvRequests.DataBind();
}
That should allow you to "Page" in essence by using controls instead of the paging feature.
** The GetYearData function is your function in which you grab your data from
** You may also want to display the current year of data your are displaying
I am dynamically adding a custom user control to an update panel. My user control contains two dropdownlists and a textbox. When a control outside of the update panel triggers a postsback, I am re-adding the user control to the update panel.
The problem is...on postback when I re-add the user controls, it's firing the "SelectedIndexChanged" event of the dropdownlists inside the user control. Even if the selectedindex did not change since the last postback.
Any ideas?
I can post the code if necessary, but there's quite a bit in this particular scenario.
Thanks in advance!
EDIT...CODE ADDED BELOW
*.ASCX
<asp:DropDownList ID="ddlColumns" OnSelectedIndexChanged="ddlColumns_SelectedChanged" AppendDataBoundItems="true" AutoPostBack="true" runat="server">
*.ASCX.CS
List<dataColumnSpecs> dataColumns = new List<dataColumnSpecs>();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
fillDDLColumns();
}
}
public void fillDataColumnsList()
{
dataColumns.Clear();
//COMMON GETDATATABLE RETURNS A DATA TABLE POPULATED WITH THE RESULTS FROM THE STORED PROC COMMAND
DataTable dt = common.getDataTable(storedProcs.SELECT_COLUMNS, new List<SqlParameter>());
foreach (DataRow dr in dt.Rows)
{
dataColumns.Add(new dataColumnSpecs(dr["columnName"].ToString(), dr["friendlyName"].ToString(), dr["dataType"].ToString(), (int)dr["dataSize"]));
}
}
public void fillDDLColumns()
{
fillDataColumnsList();
ddlColumns.Items.Clear();
foreach (dataColumnSpecs dcs in dataColumns)
{
ListItem li = new ListItem();
li.Text = dcs.friendlyName;
li.Value = dcs.columnName;
ddlColumns.Items.Add(li);
}
ddlColumns.Items.Insert(0, new ListItem(" -SELECT A COLUMN- ", ""));
ddlColumns.DataBind();
}
protected void ddlColumns_SelectedChanged(object sender, EventArgs e)
{
//THIS CODE IS BEING FIRED WHEN A BUTTON ON THE PARENT *.ASPX IS CLICKED
}
*.ASPX
<asp:UpdatePanel ID="upControls" runat="server">
<ContentTemplate>
<asp:Button ID="btnAddControl" runat="server" Text="+" OnClick="btnAddControl_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:Button ID="btnGo" runat="server" Text="Go" OnClick="btnGo_Click" ValidationGroup="vgGo" />
<asp:GridView...
*.ASPX.CS
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
uc_Counter = 0;
addControl();
gridview_DataBind();
}
else
{
reloadControls();
}
}
protected void btnGo_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
//THIS BUTTON CLICK IS WHAT'S TRIGGERING THE
//SELECTEDINDEXCHANGED EVENT TO FIRE ON MY *.ASCX
gridview_DataBind();
}
}
private void reloadControls()
{
int count = this.uc_Counter;
for (int i = 0; i < count; i++)
{
Control myUserControl = Page.LoadControl("~/Controls/myUserControl.ascx");
myUserControl.ID = "scID_" + i;
upControls.ContentTemplateContainer.Controls.AddAt(i, myUserControl);
((customUserControl)myUserControl).fillDDLColumns();
}
}
private void addControl()
{
Control myUserControl = Page.LoadControl("~/Controls/myUserControl.ascx");
myUserControl.ID = "scID_" + uc_Counter.ToString();
upControls.ContentTemplateContainer.Controls.AddAt(upControls.ContentTemplateContainer.Controls.IndexOf(btnAddControl), myUserControl);
//((customUserControl)myUserControl).fillDDLColumns();
this.uc_Counter++;
}
protected int uc_Counter
{
get { return (int)ViewState["uc_Counter"]; }
set { ViewState["uc_Counter"] = value; }
}
Even though this is already answered I want to put an answer here since I've recently tangled with this problem and I couldn't find an answer anywhere that helped me but I did find a solution after a lot of digging into the code.
For me, the reason why this was happening was due to someone overwriting PageStatePersister to change how the viewstate hidden field is rendered. Why do that? I found my answer here.
One of the greatest problems when trying to optimize an ASP.NET page to be more search engine friendly is the view state hidden field. Most search engines give more score to the content of the firsts[sic] thousands of bytes of the document so if your first 2 KB are view state junk your pages are penalized. So the goal here is to move the view state data as down as possible.
What the code I encountered did was blank out the __VIEWSTATE hidden fields and create a view_state hidden field towards the bottom of the page. The problem with this is that it totally mucked up the viewstate and I was getting dropdownlists reported as being changed when they weren't, as well as having all dropdownlists going through the same handler on submit. It was a mess. My solution was to turn off this custom persister on this page only so I wouldn't have to compensate for all this weirdness.
protected override PageStatePersister PageStatePersister
{
get
{
if (LoginRedirectUrl == "/the_page_in_question.aspx")
{
return new HiddenFieldPageStatePersister(Page);
}
return new CustomPageStatePersister(this);
}
}
This allowed me to have my proper viewstate for the page I needed it on but kept the SEO code for the rest of the site. Hope this helps someone.
I found my answer in this post .net DropDownList gets cleared after postback
I changed my counter that I was storing in the viewstate to a session variable.
Then I moved my reloadControls() function from the Page_Load of the *.ASPX to the Page_Init.
The key was dynamically adding my user control in the Page_Init so it would be a member of the page before the Viewstate was applied to controls on the page.
i'm using a HtmlInputCheckBox in a repeater by adding
<input id="CheckBox1" type="checkbox" runat="server" value='<%# Eval ("userid") %>' />
to repeater->ItemTemplate->table->tr->td and in the server side i'm using
protected void Button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < UserRepeater.Items.Count; i++)
{
var chkBox = UserRepeater.Items[i].FindControl("CheckBox1") as HtmlInputCheckBox;
if (chkBox != null && chkBox.Checked)
{
//
}
}
}
i'm not programatically setting any checkbox to set - i'm checking them on the web page during test.
my var checkbox is always inchecked {Value = "1,2,3,4" Checked = false}, thx for helping me with that.
How are you populating your repeater - if you are doing it in page_load make sure it is protected for postbacks:
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
// populate your data
}
}
EDIT
This is assuming you are working with viewstate on - which is the case by default.
This may be to do with when you bind your repeater. If you are binding on Page_Load, the check boxes will be created after viewstate and post variables have been restored, so the value won't be on your checkboxes.
If possible, move the data bind to Page_Init; as this happens before viewstate/post values are restored your checkboxes will get the right values assigned. If you can't bind on Page_Init, then #Aristos's answer will do.
' />
I want to access the value in the hidden field in my code behind. I know i need to do this when the item is bound but i cant seem to work out how to do it.
protected void addLabelsWhereNeeded(object sender, EventArgs e)
{
// Get Value from hiddenfield
}
Try adding
OnRowDataBound="addLabelsWhereNeeded"
to your GridView. Then cast the control in the corresponding cell to a HiddenField to grab the value:
protected void addLabelsWhereNeeded(object sender, GridViewRowEventArgs e)
{
HiddenField hf = e.Row.Cells[0].Controls[1] as HiddenField;
String theValue = hf.Value;
}
assuming you've defined your GridView as:
<asp:GridView runat="server" ID="gv" OnRowDataBound="addLabelsWhereNeeded">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<%--your hidden field--%>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Just make sure you are indexing the correct cell and correct control within that cell.
yes you are right. You must do it on ItemDateBound. Check It must work
I do quite see what you want to achieve with this private field while databinding? In the RowDataBound Event you can access the whole data item, so there is no need for the use of a hidden value.
Pseudocode:
protected void Grid1_RowDataBound(object sender, GridViewRowEventArgs)
{
if(e.RowType == RowType.DataRow)
{
}
}
Set a Breakpoint into if clause and use quickwatch to see how you need to cast the DataItem that is currently bound to gain full access to all properties, even if they aren't bound to any control.