LinkButton passing multivalue possible clean solutions - c#

I once asked for a way to let a linkbutton pass more than one value in the commandArgument and then I reached the approach where I pass a string of multiple values separated by any character and split it into it's original parts...that didn't work out I don't know what was wrong with the splitting!
Now I tried the only solution I got, which is created a user control of the LinkButton and add properties to accept any values nedeed!...could you please tell me what's wrong with my 2 approaches and which is better ?
The first question can be found here : link text
and this is the code for the user control approach >>
MultivaluedLinkButton.ascx :
<asp:LinkButton ID="LnkBtnSort" runat="server" Text="Sort" OnClick="LnkBtnSort_Clicked"/>
MultivaluedLinkButton.ascx.cs :
public partial class MultivaluedLinkButton : System.Web.UI.UserControl
{
public event EventHandler Click;
private int _sortingType;
private string _sortingFactor;
private string _text;
public int SortingType
{
set { _sortingType = value; }
get { return _sortingType; }
}
public string SortingFactor
{
set { _sortingFactor = value; }
get { return _sortingFactor.ToString(); }
}
//public string Text
//{
// set { _text = value; }
// get { return _text.ToString(); }
//}
protected void LnkBtnSort_Clicked(object sender, EventArgs e)
{
if( Click != null )
{
this.Click(this, EventArgs.Empty);
}
}
}
Finally, Here's the implementation of my control inside an aspx page:
protected void MultivaluedLinkButton1_Clicked(object sender, EventArgs e)
{
MultivaluedLinkButton ctrl = (MultivaluedLinkButton)sender;
using (SqlConnection cn1 = new SqlConnection(ConfigurationManager.ConnectionStrings["testConnectionString"].ConnectionString))
{
using (SqlCommand cm1 = new SqlCommand(commandString2, cn1))
{
cm1.Parameters.Add("#arrange_by_id", System.Data.SqlDbType.Int);
cm1.Parameters["#arrange_by_id"].Value = ctrl.SortingType;
cn1.Open();
using (SqlDataReader dr1 = cm1.ExecuteReader())
{
SortBy_rpt.DataSource = dr1;
SortBy_rpt.DataBind();
}
}
}
}
The item template of the repeater in the implementation page :
<ItemTemplate>
<uc1:MultivaluedLinkButton ID="MultivaluedLinkButton1" runat="server" OnClick="MultivaluedLinkButton1_Clicked" SortingType='<%#Eval("arrange_by_id")%>' />
</ItemTemplate>

The problem i see is, you have an eventHandler in your usercontrol which you never really use.
Not 100% sure but, on the Page_Load of your parent page, you need to add MultivaluedLinkButton1_Clicked event to your handler.
MultivaluedLinkButton1.EventHandler_Click = new EventHandler(this.MultivaluedLinkButton1_Clicked);
MultivaluedLinkButton1.LnkBtnSort.Click = MultivaluedLinkButton1.EventHandler_Click;
Basically you are telling that when a user clicks on your linkbutton, MultivaluedLinkButton1_Clicked() on the parent page should be called.
You can remove OnClick="MultivaluedLinkButton1_Clicked" from your UserControl properties on your parent page.

Related

Programically adding child controls to a asp.net composite control

Not found anything that directly answers my problem, so hopefully someone can shed some light on it.
I have two Composite Controls, lets call them BudgetTable and BudgetTableItem, where BudgetTable contains a list of BudgetTableItem.
So far everything works so long as I add new RowItems in the HTML View - when I add one programmatically it appears, but doesn't survive postback.
I can only assume I'm doing something boneheaded with ViewState, and would appreciate any pointers!
Thanks in advance.
The HTML:
<hea:BudgetTable runat="server" ID="btTest" MaximumFundingAvailable="7000" CssClass="bob">
<Items>
<hea:BudgetTableItem runat="server" Description="Test1" />
<hea:BudgetTableItem runat="server" Description="Test2" />
<hea:BudgetTableItem runat="server" Description="Test3" />
</Items>
</hea:BudgetTable>
The code behind:
[PersistenceMode(PersistenceMode.InnerProperty)]
[ParseChildren(true)]
public class BudgetTableItem : CompositeControl {
private TextBox _description = new TextBox();
private TextBox _cost = new TextBox();
private CheckBox _heaFunded = new CheckBox();
/*public delegate void AddRow();
public delegate void RemoveRow(BudgetTableItem item);
public event AddRow AddNewRow;
public event RemoveRow RemoveNewRow;*/
public string ItemName {
get {
var viewstate = ViewState["ItemName"];
return (viewstate is string) ? (string)viewstate : "default";
}
set {
ViewState["ItemName"] = value;
}
}
public bool ShowRemoveRow {
get {
var viewstate = ViewState["ShowRemoveRow"];
return (viewstate != null && viewstate is bool) ? (bool)viewstate : false;
}
set {
ViewState["ShowRemoveRow"] = value;
}
}
public bool ShowAddRow {
get {
var viewstate = ViewState["ShowAddRow"];
return (viewstate != null && viewstate is bool) ? (bool)viewstate : false;
}
set {
ViewState["ShowAddRow"] = value;
}
}
public string Description {
get {
return _description.Text;
}
set {
_description.Text = value;
}
}
public decimal Cost {
get {
decimal cost =0;
decimal.TryParse(_cost.Text, out cost);
return cost;
}
set {
_cost.Text = value.ToString();
}
}
public bool HeaFunded {
get {
return _heaFunded.Checked;
}
set {
_heaFunded.Checked = value;
}
}
protected override void CreateChildControls() {
Controls.Clear();
HtmlTableCell tableCell1 = new HtmlTableCell();
HtmlTableCell tableCell2 = new HtmlTableCell();
HtmlTableCell tableCell3 = new HtmlTableCell();
HtmlTableCell tableCell4 = new HtmlTableCell();
tableCell1.Attributes.Add("class", "col1");
tableCell2.Attributes.Add("class", "col2");
tableCell3.Attributes.Add("class", "col3");
tableCell4.Attributes.Add("class", "col4");
tableCell1.Controls.Add(_description);
tableCell2.Controls.Add(_cost);
tableCell3.Controls.Add(_heaFunded);
/*if (ShowAddRow || ShowRemoveRow) {
Button addNewButton = new Button();
addNewButton.Text = (ShowAddRow) ? "Add Row" : "Remove";
if (ShowAddRow) {
addNewButton.Click += new EventHandler(addNewButton_Click);
}
if (ShowRemoveRow) {
addNewButton.Click += new EventHandler(removeButton_Click);
}
tableCell4.Controls.Add(addNewButton);
}
else{*/
tableCell4.InnerHtml = " ";
//}
Controls.Add(tableCell1);
Controls.Add(tableCell2);
Controls.Add(tableCell3);
Controls.Add(tableCell4);
}
/*void addNewButton_Click(object sender, EventArgs e) {
if (AddNewRow != null) {
AddNewRow();
}
}*/
/*void removeButton_Click(object sender, EventArgs e) {
if (RemoveNewRow != null) {
RemoveNewRow(this);
}
}*/
protected override void RecreateChildControls() {
EnsureChildControls();
}
public override void RenderBeginTag(HtmlTextWriter writer) {
writer.Write("<tr>");
}
public override void RenderEndTag(HtmlTextWriter writer) {
writer.Write("</tr>");
}
}
Controls, custom or otherwise that require a ViewState and wish to receive events should be created in Init.
Http is stateless. Your entire page with all its controls is recreated on every postback. Controls that you add in the design view, are added to your designer.cs file, and created for you. When you add controls yourself, you must write code to recreate the controls on every PostBack that occurs later.
You can use the session to remember which controls were added by code and add them on later PostBacks.

Why OnClick event of a button inside usercontrol not happening

.NET pros out there
I have a problem that i would like to share with you and if possible get an advice:
I am loading a usercontrol dynamically using datalist. i am loading this usercontrol for each row i get from the database, it could be 30 different instanses of this control.
when a user click the button, i want to be able to get the values of this specific usercontrol's properties, in my understanding, i heed the usercontrol ID to do that, thats why i want to assign my "custom id" to each loaded control so i will be able to find it later.
maybe i am missing something, maybe this is not the best way, im open to suggestions.
anyway.....
UserControl code behind:
public partial class SearchBullet : System.Web.UI.UserControl
{
public static int i = 0;
private string casterLOGO;
public string CasterLOGO
{
get { return casterLOGO; }
set { casterLOGO = value; }
}
private string casterNameSB;
public string CasterNameSB
{
get { return casterNameSB; }
set { casterNameSB = value; }
}
private string player1NameSB;
public string Player1NameSB
{
get { return player1NameSB; }
set { player1NameSB = value; }
}
private string player2NameSB;
public string Player2NameSB
{
get { return player2NameSB; }
set { player2NameSB = value; }
}
private string mapSB;
public string MapSB
{
get { return mapSB; }
set { mapSB = value; }
}
private string gameFrameSB;
public string GameFrameSB
{
get { return gameFrameSB; }
set { gameFrameSB = value; }
}
private string serieSB;
public string SerieSB
{
get { return serieSB; }
set { serieSB = value; }
}
private string race1SB;
public string Race1SB
{
get { return race1SB; }
set { race1SB = value; }
}
private string race2SB;
public string Race2SB
{
get { return race2SB; }
set { race2SB = value; }
}
private string castURLSB;
public string CastURLSB
{
get { return castURLSB; }
set { castURLSB = value; }
}
private string likeAmountSB;
public string LikeAmountSB
{
get { return likeAmountSB; }
set { likeAmountSB = value; }
}
private string qRYstring;
public string QRYstring
{
get { return qRYstring; }
set { qRYstring = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
i++;
this.PreRender += new EventHandler(Cast_PreRender);
this.ID = "Result" + i.ToString();
}
PlayButton.ID = i.ToString();
}
void Cast_PreRender(object sender, EventArgs e)
{
PlayerName1.Text = Player1NameSB;
PlayerName2.Text = Player2NameSB;
CasterName.Text = CasterNameSB;
ImageRace1.ImageUrl = Race1SB;
ImageRace2.ImageUrl = Race2SB;
Map.Text = MapSB;
GameFrame.Text = GameFrameSB;
LikeAmount.Text = LikeAmountSB;
CasterLOGOIMG.ImageUrl = CasterLOGO;
PlayButton.AlternateText = "yay";
}
protected void PlayButton_Click1(object sender, ImageClickEventArgs e)
{
Image img = (Image)sender;
string tt = img.AlternateText;
int j = 0;
Response.Redirect("default2.aspx");
// lb.Text = img.ClientID;
}
}
The aspx page:
<asp:DataList ID="WatchLaterDL" runat="server" DataSourceID="SDSWatchLater" RepeatColumns="1">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<Search:Bullet runat="server" EnableViewState="false" ID="SearchResults" Player1NameSB='<%#Bind("Player_Name") %>'
Player2NameSB='<%#Bind("Expr1") %>' CasterNameSB='<%#Bind("Caster_Name") %>'
Race1SB='<%#Bind("Race_1") %>' Race2SB='<%#Bind("Race_2") %>' MapSB='<%# Bind("Map")%>'
GameFrameSB='<%#Bind("Game_Frame") %>' LikeAmountSB='<%#Bind("Like_Amount") %>'
CastURLSB='<%#Bind("Cast_URL") %>' CasterLOGO='<%#Bind ("Caster_LOGO") %>' />
</ItemTemplate>
<SeparatorTemplate>
<br />
</SeparatorTemplate>
</asp:DataList></div>
the problem is, after doing this, when i click the button nothing happens, i mean, when debugging, i never get inside the OnButton_Click event. if i delete the --> this.ID = "Result" + i.toString(); and the--> PlayButton.ID = i.ToString(); it's ok.
if there anything elese you might need to evaluate my problem, ill gladly prove and additional code needed.
thank you very much for your help.
Check out the itemcommand for the datalist.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.datalist.itemcommand%28v=vs.71%29.aspx
my solution was like this:
instead of using an image buttom, i used Hyperlink.
on_Load event of the usercontrol, i assigned to the src Attribute of the hyperlink all the properties of my user control and passed those using
querystring to another page.

Can I save a postback status and restore it?

Suppose that, after a click on a asp:button, I'd like to store the actual "view", with selected value for each controllers, like asp:checkbox, or input inserted by users on inputbox.
Than, I change page, with a link such as "back to the previous page". I'd like so "restore" the old actual form, before leaving it.
Is it possible with .NET? Or I need to implements all controls in variables and put them in session?
There are several ways how you can persist or pass values between ASP.NET pages.
Have a look here for more informations.
Because you've mentioned that you have "tons" of controls to store and restore, i've tried to find a way to automatize this process.
Here's my approach which uses Session as storage to persist all controls' values of type IPostBackDataHandler. Not really tested but hopefully helpful anyway.
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
public class FormStorage
{
private System.Web.UI.Page _page = null;
public Dictionary<String, Dictionary<String, String>> storage
{
get { return (Dictionary<String, Dictionary<String, String>>)_page.Session["FormStorage"]; }
set { _page.Session["FormStorage"] = value; }
}
public FormStorage(System.Web.UI.Page page)
{
_page = page;
initHandler();
if (this.storage == null)
{
this.storage = new Dictionary<String, Dictionary<String, String>>();
}
if(!this.storage.ContainsKey(_page.Request.Path))
this.storage.Add(_page.Request.Path, new Dictionary<String, String>());
}
private void initHandler()
{
_page.Init += Init;
_page.Load += Load;
}
private void Init(Object sender, EventArgs e)
{
loadForm();
}
private void Load(Object sender, EventArgs e)
{
saveForm();
}
private void loadForm()
{
var pageStorage = storage[_page.Request.Path];
var e = pageStorage.GetEnumerator();
while (e.MoveNext())
{
loadControl(e.Current.Key, e.Current.Value);
}
}
private void loadControl(String ID, String value)
{
Control control = findControlRecursively(_page, ID);
if (control != null)
{
setControlValue(control, value);
}
}
private void setControlValue(Control control, String value)
{
if (control is ITextControl)
{
ITextControl txt = (ITextControl)control;
txt.Text = value == null ? "" : value;
}
else if (control is ICheckBoxControl)
{
ICheckBoxControl chk = (ICheckBoxControl)control;
chk.Checked = value != null;
}
else if (control is ListControl)
{
ListControl ddl = (ListControl)control;
if (value == null)
ddl.SelectedIndex = -1;
else
ddl.SelectedValue = value;
}
}
public void saveForm()
{
saveControlRecursively(this._page);
}
private void saveControlRecursively(Control rootControl)
{
if (rootControl is IPostBackDataHandler)
{
var postBackData = _page.Request.Form[rootControl.ID];
storage[_page.Request.Path][rootControl.ID] = postBackData;
}
if (rootControl.HasControls())
foreach (Control subControl in rootControl.Controls)
saveControlRecursively(subControl);
}
private static Control findControlRecursively(Control rootControl, String idToFind)
{
if (rootControl.ID == idToFind)
return rootControl;
foreach (Control subControl in rootControl.Controls)
{
Control controlToReturn = findControlRecursively(subControl, idToFind);
if (controlToReturn != null)
{
return controlToReturn;
}
}
return null;
}
}
Here's an examplary implementation in a page that redirects to another page:
private FormStorage storage;
protected void Page_PreInit(object sender, EventArgs e)
{
storage = new FormStorage(this);
}
protected void BtnRedirect_Click(object sender, EventArgs e)
{
Response.Redirect("RedirectForm.aspx");
}
Note that it loads and saves implicitely on Page_Load/Page_PreRender. Therefor the FormStorage instance must be created in Page_PreInit.
If you want to change values after Page_Load programmatically, you need to call storage.saveForm() manually (for example in Page_PreRender) to ensure that these values are overridden, because FormStorage will auto-save all postback data in Page_Load.
Edit: The history.go approach of sh4nx0r is probably better since it's more scalable. My approach uses the Session and would not be appropriate for an internet-application with a huge amount of (possible) users.
One (small) advantage of mine is that it would work even when javascript is disabled. One larger advantage is that you can control to what page you want to redirect. You can even restore values across multiple redirects.
You don't need sessions to do this. Just make use of JavaScript.
Consider you have two pages Page1.aspx and Page2.aspx.
You have textboxes , checkboxes , radiobuttons on Page1.aspx and you have a button "Submit". By clicking the button it takes to Page2.aspx.
Just have a button "Back to Previous Page" on Page2.aspx , which on clicking takes you to Page1.aspx with all those values still being there. To do this, Add this line on your Page2.aspx page_load event
protected void Page_Load(object sender, EventArgs e)
{
btnBackButton.Attributes.Add("onClick", "javascript:window.history.go(-1);return false;");
}

Increment number per button click C# ASP.NET [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Button click event doesn't work properly
I try to increment an int for each click on a default page. Int=0. It only goes up to 1. What should I do to increment the number for each click?
public partial class _Default : System.Web.UI.Page
{
private int speed = 0;
public int Speed
{
get { return speed; } // Getter
set { speed = value; } // Setter
}
public void accelerate()
{
//speed++;
this.Speed = this.Speed + 1;
}
public void decelerate()
{
// speed--;
this.Speed = this.Speed - 1;
}
public int showspeed()
{
return this.Speed;
}
//car bmw = new car();
public void Page_Load(object sender, EventArgs e)
{
//datatype objectname = new
dashboard.Text = Convert.ToString(this.showspeed());
}
public void acc_Click(object sender, EventArgs e)
{
this.accelerate();
dashboard.Text = Convert.ToString(this.showspeed());
}
public void dec_Click(object sender, EventArgs e)
{
this.decelerate();
this.showspeed();
}
}
You could use the ViewState to maintain the value across postbacks:
private int Speed
{
get
{
if (ViewState["Speed"] == null)
ViewState["Speed"] = 0;
return (int)ViewState["Speed"];
}
set { ViewState["Speed"] = value; }
}
You need to store the result in a way that will persist over postback. I suggest using ViewState, for example:
public int Speed
{
get {
if(ViewState["Speed"] == null) {
ViewState["Speed"] = 1;
}
return Convert.ToInt32(ViewState["Speed"]);
}
set {
ViewState["Speed"] = value;
}
}
Because everytime when you click on the button, it is initializing the value of speed to 0.
HTTP is stateless. That means it wil not retain the values of variable across your postback like you do in Windows Forms programming. So you need to keep the value across your postbacks.
You can use a hidden element in your page to store the value and access the value every time you want to do a function on that:
<asp:HiddenField ID="hdnFileId" runat="server" Value="" />
and in your page load, you can read the value and load it to your variable.
public void Page_Load(object sender, EventArgs e)
{
this.speed = ConvertTo.Int32(hdnFileId.Value);
}
From Adrianftode's comment, the data for the controls like TextBox, Checkbox, Radio button controls values will be posted to the server on the postback because they are rendered as standard HTML form controls in the browser. See Chapter 4. Working with ASP.NET Server Controls.

Custom Paging Repeater Control next and previous events happen after databind

I have a Custom Repeater control that inherits from Repeater and has paging functionality, however when I click the next page button the first time it refreshes the control but does not change the page, if I click it again after that it changes page perfectly.
I know what the issue is, when I click the next button it does a postback, then the data is bound to the repeater, and then after that the NextButton Event is handled.
Is there any way I can change the order of the page load events?? Or force the repeater to reload again after the event is handled??
I've included my Custom Repeater class bellow:
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Data;
using System.Collections;
using System;
namespace ASPresentation.Controls
{
[ToolboxData("<cc:PagedRepeater runat=server></cc:PagedRepeater>")]
public class PagedRepeater : Repeater
{
public int PageSize { get; set; }
public int CurrentPageIndex
{
get
{
return Convert.ToInt16(Page.Session["ProjectIndex"]);
}
set
{
Page.Session.Add("ProjectIndex", value);
}
}
public PagedDataSource pagedData = new PagedDataSource();
LinkButton NextBtn = new LinkButton();
LinkButton PrevBtn = new LinkButton();
public bool IsLastPage
{
get
{
return pagedData.IsLastPage;
}
}
public bool IsFirstPage
{
get
{
return pagedData.IsFirstPage;
}
}
public override object DataSource
{
get
{
return base.DataSource;
}
set
{
pagedData.DataSource = (IEnumerable)value;
}
}
protected void NextButtonClick(object sender, EventArgs e)
{
if (!IsLastPage)
{
CurrentPageIndex++;
}
}
protected void PrevButtonClick(object sender, EventArgs e)
{
if (!IsFirstPage)
{
CurrentPageIndex--;
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
NextBtn.Text = "Next";
PrevBtn.Text = "Prev";
NextBtn.Click += new EventHandler(NextButtonClick);
PrevBtn.Click += new EventHandler(PrevButtonClick);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
base.Controls.Add(PrevBtn);
base.Controls.Add(NextBtn);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
}
public override void DataBind()
{
pagedData.AllowPaging = true;
pagedData.PageSize = PageSize;
pagedData.CurrentPageIndex = CurrentPageIndex;
base.DataSource = pagedData;
base.DataBind();
}
}
}
A couple issues here that jump out at me.
One, why are you dynamically creating the prev/next button? Just put them in the ASCX. Show/hide them if you like based on whether your page index is first/last. If you must create them dynamically, do so in Init...
Two, do not store your page index in the session like that. What happens when you have two of these custom repeaters on one page? Use the ViewState. Key the string name to the control ID if necessary, but I think ViewState does this automatically(?).
Finally, what is triggering the DataBind? What event handler? It must be called from the Page that is hosting this control. If that's the case, then you also need to expose the Next/Prev clicks as events so that DataBind can be called in response to these events. This is how Microsoft's controls that handle paging work, such as the GridView. NextBtn.Click or PrevBtn.Click is guaranteed to be the last postback event handled.
You could handle the next/prev internally, but if you're going to do that you need to also call DataBind() in your code, so that it happens at the correct time.
Call "this.DataBind()" in the Page change functions.
This will mean you databind twice when changing pages but will work :-\

Categories

Resources