Why OnClick event of a button inside usercontrol not happening - c#

.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.

Related

MouseClickEvent for a UserControl doesn't fire when its Children are clicked

Sorry for my query but I am just a beginner in using UserControl:
Why do MouseClickEvent of a UserControl doesn't get inherited by the controls (e.g Labels) inside it?
To show you how I instantiate the UserControl inside a flowLayoutPanel:
studentItemList[] listItem = new studentItemList[dt.Rows.Count];
for (int i = 0; i < listItem.Length; i++)
{
listItem[i] = new studentItemList();
listItem[0].Anchor = AnchorStyles.Right;
listItem[i].MouseDoubleClick += StudentPrev;
listItem[i].StudentID = dt.Rows[i].Field<string>(0);
listItem[i].StudentName = dt.Rows[i].Field<string>(1) + ", " + dt.Rows[i].Field<string>(2) + " " + dt.Rows[i].Field<string>(3);
listItem[i].StudentEmail = dt.Rows[i].Field<string>(4);
listItem[i].StudentStatus = dt.Rows[i].Field<string>(5);
flowLayoutPanelStudents.Controls.Add(listItem[i]);
}
studentItemList.cs:
public partial class studentItemList : UserControl
{
public studentItemList()
{
InitializeComponent();
}
private string _studID, _studName, _studEmail, _status;
public string StudentID
{
get { return _studID; }
set { _studID = value; studentNo.Text = value; }
}
public string StudentName
{
get { return _studName; }
set { _studName = value; studentName.Text = value; }
}
private void studentNo_Click(object sender, EventArgs e)
{
}
public string StudentEmail
{
get { return _studEmail; }
set { _studEmail = value; studentEmail.Text = value; }
}
public string StudentStatus
{
get { return _status; }
set { _status = value; status.Text = value; }
}
private void label1_Click(object sender, EventArgs e)
{
}
}
Label.Autosize is set to true and DockStyles are set to Left.
Although, the MouseEvent get's triggered when the parent Panel of the UserControl is clicked.
What's the reason behind this?
You need to wire up all controls that may receive a click event.
If all controls in yout user control are added before the control is instantiated (e.g. design-time) then you can add event handlers in the user control's constructor.
If the user control has controls added/removed at run-time then you'll need to wire up ControlAdded and ControlRemoved events to wire/unwire events.

How to fix missing DataKeys in Viewstate when using custom PageStatePersister

We have a website using Webforms. We want to use a custom PageStatePersister which saves the viewstate into a redis cache (see code below). On page level we override the PageStatePersister property to use our PageStatePersister. All works fine so far, but when we have a control within another control, we encounter a few issues.
public class RedisPageStatePersister : PageStatePersister
{
const string ViewStateFieldName = "__VIEWSTATEKEY";
const string ViewStateKeyPrefix = "ViewState_";
public RedisPageStatePersister(Page page) : base(page)
{
}
public override void Load()
{
var key = Page.UniqueID;
// The cache key for this viewstate is stored in a hidden field, so grab it
string viewStateKey = Page.Request.Form[ViewStateFieldName] as string;
// Grab the viewstate data using the key to look it up
if (viewStateKey != null)
{
var database = RedisConnectorHelper.Connection.GetDatabase(1);
var viewstate = database.StringGet(viewStateKey);
if (!viewstate.IsNull)
{
Pair p = (Pair)StateFormatter.Deserialize(database.StringGet(viewStateKey));
ViewState = p.First;
ControlState = p.Second;
}
}
}
public override void Save()
{
string viewStateKey = Page.Request.Form[ViewStateFieldName] as string;
if (viewStateKey == null)
{
viewStateKey = ViewStateKeyPrefix + Guid.NewGuid().ToString();
}
// Put viewstate data on writer
var viewStateSerialized = StateFormatter.Serialize(new Pair(base.ViewState, base.ControlState));
// Store the viewstate's key in a hidden field, so on postback we can grab it from the cache
Page.ClientScript.RegisterHiddenField(ViewStateFieldName, viewStateKey);
// Get the Redis database
var database = RedisConnectorHelper.Connection.GetDatabase(1);
// Save viewstate to the database
database.StringSet(viewStateKey, viewStateSerialized, TimeSpan.FromMinutes(15));
}
}
For example:
When using ListViews. We have a ListView with DataKeys within another ListView. On postback, the datakeys are not restored for the nested ListView
<asp:ListView runat="server" ID="lvOuter" DataKeyNames="These,Keys,Work">
<ItemTemplate>
<asp:ListView runat="server" ID="lvInner" DataKeyNames="These,Keys,Dont,Work">
<ItemTemplate></ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
We use dynamic creates TabPanel with GridView within. The GridView within loose their datakeys values on postback
The problem only seems to encounter for DataKeys, the use of HiddenField for example is no problem.
I also tried to use the SessionPageStatePersister, since this is a built-in persister, but here too the problem occurs
Below a code snippet where dummy data is bound to a listview and its inner listview. The error occurs when clicking on the button and trying to retrieve the datakey values of the inner listview. The property "DataKeys" is an empty list, so a IndexOutOfRangeException is thrown.
public partial class InnerListViewTest : Page
{
public class Outer
{
public List<Inner> Inner { get; set; }
public string Key1 { get; set; }
public string Key2 { get; set; }
}
public class Inner
{
public string InnerKey1 { get; set; }
public string InnerKey2 { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var data = new List<Outer>();
for (int i = 0; i < 5; i++)
{
data.Add(new Outer()
{
Inner = new List<Inner>()
{
new Inner() {
InnerKey1 = "InnerData1_" + i,
InnerKey2 = "InnerData2_" + i
},
new Inner() {
InnerKey1 = "InnerData3_" + i,
InnerKey2 = "InnerData4_" + i
},
new Inner() {
InnerKey1 = "InnerData5_" + i,
InnerKey2 = "InnerData6_" + i
}
},
Key1 = "Data1_" + i,
Key2 = "Data2_" + i
});
}
lvOuter.DataSource = data;
lvOuter.DataBind();
}
}
protected void lvOuter_ItemDataBound(object sender, ListViewItemEventArgs e)
{
var outerData = e.Item.DataItem as Outer;
var lvInner = e.Item.FindControl("lvInner") as ListView;
lvInner.DataSource = outerData.Inner;
lvInner.DataBind();
}
protected void Unnamed_Click(object sender, EventArgs e)
{
foreach (ListViewItem outerItem in lvOuter.Items)
{
var lvInner = outerItem.FindControl("lvInner") as ListView;
foreach (ListViewItem innerItem in lvInner.Items)
{
var innerKey1 = lvInner.DataKeys[innerItem.DataItemIndex]["InnerKey1"];
var innerKey2 = lvInner.DataKeys[innerItem.DataItemIndex]["InnerKey2"];
}
}
}
}
The problem is probably with the pagepersister, but i cant seem to find out why!
I already found my own answer! The PageStatePersister had to be enabled using a PageAdapter instead of overriding the property of the Page!

Textbox rendered as label

I have created a custom web server control that will have a bool property 'RenderAsLabel' so that I can convert textboxes to labels, for Read-only forms. I was wondering if there is any reason why this code should not be safe, or work as intended. Upon initial testing it seems fine, but I just want to make sure I'm not doing something that will end up causing issues.
namespace OrmControlLibrary
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:OrmTextBox ID='' runat=server ></{0}:OrmTextBox>")]
public class OrmTextBox : TextBox
{
private Label lbl;
public virtual bool RenderAsLabel
{
get
{
if (ViewState["OrmTextBox"] == null)
{
return false;
}
else
{
return (bool)ViewState["OrmTextBox"];
}
}
set
{
ViewState["OrmTextBox"] = value;
}
}
protected override void Render(HtmlTextWriter w)
{
if (RenderAsLabel)
{
SetLabelProperties();
lbl.RenderControl(w);
}
else
{
base.Render(w);
}
}
private void SetLabelProperties()
{
lbl = new Label();
lbl.ID = this.ID;
lbl.CssClass = this.CssClass;
lbl.Text = this.Text;
}
}
}

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.

LinkButton passing multivalue possible clean solutions

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.

Categories

Resources