Showing posts with label across. Show all posts
Showing posts with label across. Show all posts

Wednesday, March 28, 2012

Dynamic Controls in ASP.NET AJAX context - Controls seem to be disappearing.

I have a Web Application that I am developing and I have run across aserious problem. Due to the fact that the Application entails a lot ofdetails and code I am not able to give an actual sample of the problemI am running into. However, I have created the same problem on asmaller scale in a temporary Application.

Theissue revolves around ASP.NET AJAX and its ability to track Dynamicallycreated Web Controls. On the sample Application below I have a Pagethat contains 8 Buttons. Whenever one of those Buttons is pressed thePage performs an Async PostBack which causes the Page Load Event toexecute followed by the Event Handler for the Button pressed. In theEvent Handler the Button gets removed from the Page. The desiredeffect is that when someone pressed a Button it will in turn remove theappropriate Web Control (Button) from the Page. Everything works finewith one very big exception: ASP.NET AJAX seems to have a problemkeeping track of the Controls on the page.

For example, if youcopy and paste the code at the bottom of this post into Visual Studioand press the Buttons in the following order you will notice someButtons simply disappearing:
2 - 7 - PostBack - 4 - 1 - PostBack

Onevery important part of this demonstration is that the Button is notonly removed but its also prevented from Rendering. If you take outthis line of code everything works fine but in my actual Applicationthe Control is not Rendered and the results match that of what happensin the temp Application.

So my question is, whats happening inthe background? It seems that removing the Control does not prevent itfrom being Rendered and if you manually prevent it from Rendering bysetting its Visible Property to False then ASP.NET gets completelythrown off as to whats going on.

I know its rather difficult toanswer a question like this because you can't simply provide analternative to the problem so any help is greatly appreciated. I amsimply trying to figure out whats going on in the background so I canfind a solution to my real Application.

Code Behind:

Partial Class _Default
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

' Clearing any previous text.
label1.text = ""

' If its the first time loading the Page
If Not Page.IsPostBack Then
Page.Session.Add("AddButton1", "True")
Page.Session.Add("AddButton2", "True")
Page.Session.Add("AddButton3", "True")
Page.Session.Add("AddButton4", "True")
Page.Session.Add("AddButton5", "True")
Page.Session.Add("AddButton6", "True")
Page.Session.Add("AddButton7", "True")
Page.Session.Add("AddButton8", "True")

Page.Session.Add("RemovalTracker", "")

' Else the page is performing a PostBack
Else
label1.text = CStr(Page.Session.Item("RemovalTracker"))
End If

'Dynamically creating the Buttons and then adding them to the Page / Form.

If CBool(Page.Session.Item("AddButton1")) = True Then
Dim button1 As New Button
button1.Text = "Button1"
button1.ID = "Button1"
AddHandler button1.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button1)
End If

If CBool(Page.Session.Item("AddButton2")) = True Then
Dim button2 As New Button
button2.Text = "Button2"
button2.ID = "Button2"
AddHandler button2.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button2)
End If

If CBool(Page.Session.Item("AddButton3")) = True Then
Dim button3 As New Button
button3.Text = "Button3"
button3.ID = "Button3"
AddHandler button3.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button3)
End If

If CBool(Page.Session.Item("AddButton4")) = True Then
Dim button4 As New Button
button4.Text = "Button4"
button4.ID = "Button4"
AddHandler button4.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button4)
End If

If CBool(Page.Session.Item("AddButton5")) = True Then
Dim button5 As New Button
button5.Text = "Button5"
button5.ID = "Button5"
AddHandler button5.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button5)
End If

If CBool(Page.Session.Item("AddButton6")) = True Then
Dim button6 As New Button
button6.Text = "Button6"
button6.ID = "Button6"
AddHandler button6.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button6)
End If

If CBool(Page.Session.Item("AddButton7")) = True Then
Dim button7 As New Button
button7.Text = "Button7"
button7.ID = "Button7"
AddHandler button7.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button7)
End If

If CBool(Page.Session.Item("AddButton8")) = True Then
Dim button8 As New Button
button8.Text = "Button8"
button8.ID = "Button8"
AddHandler button8.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button8)
End If

End Sub

Protected Sub testSub(ByVal sender As Object, ByVal e As System.EventArgs)

' Appending the Button Text to SessionState.
Page.Session.Item("RemovalTracker") = Page.Session.Item("RemovalTracker") & " - " & CType(sender, Button).Text

' Building the ID for the Session Item that needs to be modified.
Dim buttonToRemove As String
buttonToRemove = "Add" & CType(sender, Button).ID
Session.Item(buttonToRemove) = "False"

' Preventing the Buttom from Rendering - this is CRUCIAL to my demonstration.
CType(sender, Button).Visible = False

Page.Form.Controls.Remove(CType(sender, Button))

End Sub

End Class

Default.aspx Page:
<%@dotnet.itags.org. Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.vb" Inherits="_Default" %
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body
<form id="form1" runat="server">

<asp:ScriptManager ID="ScriptManager1" runat="server" />

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<br />
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
<br />
<br />
<br />
<asp:Button ID="ButtonPostBack" runat="server" Text="PostBack" />
<br />
<br />
</ContentTemplate>
</asp:UpdatePanel
</form>

</body>
</html>

After 3+ days of brainstorming, testing, debugging and everything I could throw at ASP.NET I have found a solution.

Theproblem lies not within ViewState, not with ASP.NET's Control Tree (nottechnically), not within the Code itself but in how ASP.NET handlesdynamic Controls in regards to their ID's.

If I modify my codeabove as demonstrated below everything works just fine. You wouldthink that incrementing the ID's instead of assinging the same ID's tothe same Controls would do nothing but for some bizarre reason thatshow it works.

My problem in my real Application is very similiarto this problem and I have in fact solved my problem. Its funny how ifI had been able to pin-point this problem several days ago I would beway beyond this. Oh well, thats ASP.NET.

ASPX Page:
<%@. Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.vb" Inherits="_Default" %
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body
<form id="form1" runat="server">

<asp:ScriptManager ID="ScriptManager1" runat="server" />

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<br />
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
<br />
<br />
<br />
<asp:Button ID="ButtonPostBack" runat="server" Text="PostBack" />
<br />
<br />
</ContentTemplate>
</asp:UpdatePanel
</form>

</body>
</html
Code Behind:
Partial Class _Default
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

' Clearing any previous text.
label1.text = ""

Dim counter As Integer = 0

' If its the first time loading the Page
If Not Page.IsPostBack Then
Page.Session.Add("AddButton1", "True")
Page.Session.Add("AddButton2", "True")
Page.Session.Add("AddButton3", "True")
Page.Session.Add("AddButton4", "True")
Page.Session.Add("AddButton5", "True")
Page.Session.Add("AddButton6", "True")
Page.Session.Add("AddButton7", "True")
Page.Session.Add("AddButton8", "True")

Page.Session.Add("RemovalTracker", "")

' Else the page is performing a PostBack
Else
label1.text = CStr(Page.Session.Item("RemovalTracker")

)
End If

'Dynamically creating the Buttons and then adding them to the Page / Form.

If CBool(Page.Session.Item("AddButton1")) = True Then
Dim button1 As New Button
button1.Text = "Button1"
button1.ID = counter.ToString
counter += 1
AddHandler button1.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button1)
End If

If CBool(Page.Session.Item("AddButton2")) = True Then
Dim button2 As New Button
button2.Text = "Button2"
button2.ID = counter.ToString
counter += 1
AddHandler button2.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button2)
End If

If CBool(Page.Session.Item("AddButton3")) = True Then
Dim button3 As New Button
button3.Text = "Button3"
button3.ID = counter.ToString
counter += 1
AddHandler button3.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button3)
End If

If CBool(Page.Session.Item("AddButton4")) = True Then
Dim button4 As New Button
button4.Text = "Button4"
button4.ID = counter.ToString
counter += 1
AddHandler button4.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button4)
End If

If CBool(Page.Session.Item("AddButton5")) = True Then
Dim button5 As New Button
button5.Text = "Button5"
button5.ID = counter.ToString
counter += 1
AddHandler button5.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button5)
End If

If CBool(Page.Session.Item("AddButton6")) = True Then
Dim button6 As New Button
button6.Text = "Button6"
button6.ID = counter.ToString
counter += 1
AddHandler button6.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button6)
End If

If CBool(Page.Session.Item("AddButton7")) = True Then
Dim button7 As New Button
button7.Text = "Button7"
button7.ID = counter.ToString
counter += 1
AddHandler button7.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button7)
End If

If CBool(Page.Session.Item("AddButton8")) = True Then
Dim button8 As New Button
button8.Text = "Button8"
button8.ID = counter.ToString
counter += 1
AddHandler button8.Click, AddressOf testSub
UpdatePanel1.ContentTemplateContainer.Controls.Add(button8)
End If

End Sub

Protected Sub testSub(ByVal sender As Object, ByVal e As System.EventArgs)

' Appending the Button Text to SessionState.
Page.Session.Item("RemovalTracker") = Page.Session.Item("RemovalTracker") & " - " & CType(sender, Button).Text

' Building the ID for the Session Item that needs to be modified.
Dim buttonToRemove As String
buttonToRemove = "Add" & CType(sender, Button).ID
Session.Item(buttonToRemove) = "False"

' Preventing the Buttom from Rendering - this is CRUCIAL to my demonstration.
CType(sender, Button).Visible = False

Page.Form.Controls.Remove(CType(sender, Button))

End Sub

Saturday, March 24, 2012

dropshadow cant have more than one panel across?

Hi,

I've just been looking at the dropshadow control and tried to make more than one panel appear horizontally next to each other. Unfortunately they seem to appear under each other vertically even when you set the width to something really low like 100px. None of your examples show more than one panel in them horizontally so I'm wondering if this is a correct limitation. And even trying absolute positioning totally breaks these panels! :(

Can you have more than one dropshadow panel across, because for my purposes it is useless without this capability?

Regards,
Andrew.

Sorry, not sure I understand. Mind posting a simple sample?


Ah, I've figured it out now.

It's a DIV CSS issue since everything is rendered to div's.

Adding the style - float: left; allows multiple div's to appear next to each other.

Andrew.


Did you know if you change RenderMode="inline" it uses Span instead?

DropDownList, UpdatePanel, ControlEventTrigger and TimerControl affecting other UpdatePane

I've run across a problem so I've created some sample code below that replicates what I'm seeing.

I've got an UpdatePanel(up_Test) that has a control in it. I've got a TimerControl that fires every 2 seconds and my UpdatePanel has a Trigger to refresh on my TimerControl's Tick event.

I've got a DropDownList on the page(ddl_Test), with an AutoPostBack="true", I've got another UpdatePanel on the page that has a Trigger to refresh on my DropDownList's SelectedIndexChanged event. In this UpdatePanel I've got another DropDownList that gets its SelectedIndex set to the SelectedIndex of the first DropDownList.

Everything works as expected, except when I test it with IE6, when the TimerControl fires, the DropDownList in the second UpdatePanel gets refreshed. It doesn't seem to happen(or at least isn't noticable) with IE7(which is on the machine I'd been writing this on).

Basically, I wrote this big page that has a ton of different updatepanel's on it each with triggers to specific controls and that whole section worked great, but then on my masterpage, when I put a gridview with a timercontrol, suddenly, the page practically became unusable as all of the updatepanels suddenly trigger when the TimerControl fires. Is there some work-around I can do, or do I just need to drop the TimerControl and scrap the whole layout?

<

atlas:TimerControlID="tc_Test"runat="server"Interval="2000"Enabled="true"OnTick="tc_Test_Tick"/><atlas:UpdatePanelID="up_Test"runat="server"><ContentTemplate><asp:DropDownListID="ddl_Test"runat="server"></asp:DropDownList></ContentTemplate><Triggers><atlas:ControlEventTriggerControlID="tc_Test"EventName="Tick"/></Triggers></atlas:UpdatePanel><asp:DropDownListID="ddl_Test1"runat="server"AutoPostBack="true"OnSelectedIndexChanged="ddl_Test1_SelectedIndexChanged"/><atlas:UpdatePanelID="up_Test2"runat="server"><ContentTemplate><asp:DropDownListID="ddl_Test2"runat="server"></asp:DropDownList></ContentTemplate><Triggers><atlas:ControlEventTriggerControlID="ddl_Test1"EventName="SelectedIndexChanged"/></Triggers></atlas:UpdatePanel>

protected

void Page_Load(object sender,EventArgs e)

{

if (!Page.IsPostBack)

{

for (int i = 0; i < 10; i++)

{

string itemtext ="This is a long string to make it noticable " + i.ToString();

ddl_Test.Items.Add(itemtext);

ddl_Test1.Items.Add(itemtext);

ddl_Test2.Items.Add(itemtext);

}

}

}

protectedvoid ddl_Test1_SelectedIndexChanged(object sender,EventArgs e)

{

ddl_Test2.SelectedIndex = ddl_Test1.SelectedIndex;

}

protectedvoid tc_Test_Tick(object sender,EventArgs e)

{

Random r=newRandom();

ddl_Test.SelectedIndex = r.Next(9);

}

Mode="Conditional" on the update panels fixes the problem. I guess I just assumed putting in the <trigger> lines caused it to use the triggers but you have to change the updatepanel's mode too.