问题
Ok so I have a problem. I am currently working on a project using the Telerik framework for ASP.NET AJAX, although that shouldnt matter much as I am bypassing Telerik completely (almost) for this portion of the work.
I'm putting together a facebook-like chat program into our company's CRM system and, while all has gone well up to this point, I've hit a roadblock. The problem is when I try to "create a new chatbox". I'm using the asp control UpdatePanel in conjunction with a jQuery $.ajax call to pass a JSON method name to my code behind file. Here's the JSON logic:
DoubleClick on user in userlist:
$telerik.$(".UserListEntry").dblclick(function () {
var ToName = $telerik.$(this).children(".UserListEntryName").text();
var FromName = $telerik.$("#lkUserGeneralSettings").text();
$telerik.$.ajax({
type: 'POST',
url: 'DefaultHandler.ashx',
data: { "ToName": ToName, "FromName": FromName },
success: CreateChatBox(),
error: function (response) { alert("error: 001"); }
});
});
CreateChatBox callback:
function CreateChatBox() {
$telerik.$.ajax({
type: 'POST',
url: 'Default.aspx',
data: { MethodName: "CreateChatBox" },
success: ForceAsyncPostback,
error: function (response) { alert("error: 002"); }
});
}
Force asyncpostback (shouldn't be necessary, but this doesnt even work either!):
function ForceAsyncPostback() {
var UpdatePanel1 = '<%=Panel3.ClientID%>';
if (UpdatePanel1 != null) {
__doPostBack(UpdatePanel1, '');
}
alert("Success");
}
The UpdatePanel is created through various literals and some hard-coded html good-ole' fashioned divs. The problem is NOT with the dynamic creation of said elements, this works just fine. In fact my code behind (which I will post below) creates and displays everything perfectly fine if I place it into my PageLoad event.
At any rate, here's the .aspx:
<asp:UpdatePanel ID="Panel3" runat="server" OnLoad="Panel3_Load" UpdateMode="Conditional">
<ContentTemplate>
<asp:Literal ID="ChatBoxesLiteralTop" runat="server" />
<asp:Literal ID="ChatBoxesLiteralMid" runat="server" />
<asp:PlaceHolder ID="ChatBoxesPlaceHolder" runat="server" />
<asp:Literal ID="ChatBoxesLiteralBot" runat="server" />
<div id="UserListCorner">
<img id="UserListBtn" src="images/list.png" />
</div>
<div id="UserList" class="UserListHidden">
<div id="UserListView">
<asp:Literal ID="UserListViewLiteral" runat="server" />
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
Code Behind:
protected void Panel3_Load(object sender, EventArgs e)
{
#region Ajax methods
if (Request.Form["MethodName"] == "CreateChatBox")
{
CreateChatBox();
}
#endregion
Engine m_engine = new Engine();
string m_sql = @"SELECT FullName FROM Users WHERE RecordDeleted <> 1";
DataTable dt = m_engine.GetObjectsAsDataTable(m_sql);
for (int i = 0; i < dt.Rows.Count; i++)
{
UserListViewLiteral.Text += "<div class='UserListEntry'><span class='UserListEntryStatus'><img src='images/status-online.png' width='10' /></span> <span class='UserListEntryName'>" + dt.Rows[i]["FullName"].ToString() + "</span></div>";
}
RadAjaxManager.GetCurrent(Page).ResponseScripts.Add("ChatAjax()");
}
private void CreateChatBox()
{
ChatBoxesLiteralTop.Text = @"<div id='ChatBox' class='ChatBoxHidden'>
<div class='ChatBoxHeader'>
<img id='ChatBoxStatusBtn' src='Images/status-online.png' />
<span id='ChatBoxUserLabel'>John Doe</span>
<img id='closeBtn' src='Images/close.png' />
<img id='toggleTab' src='Images/up-arrow.png' />
</div>
<div id='ChatBoxMessageOutput'></div><div class='ChatBoxFooter'>";
TextBox txt = new TextBox();
txt.ID = "ChatBoxMessageInput";
txt.Height = 16;
txt.MaxLength = 270;
txt.Width = 250;
txt.AutoPostBack = false;
ChatBoxesPlaceHolder.Controls.Add(txt);
RadButton btn = new RadButton();
btn.ID = "ChatBoxSendButton";
btn.Text = "Send";
btn.AutoPostBack = true;
btn.Height = 22;
btn.Click += ChatBoxSendButton_Click;
ChatBoxesPlaceHolder.Controls.Add(btn);
ChatBoxesLiteralBot.Text = "</div></div>";
Panel3.Update();
RadAjaxManager.GetCurrent(Page).ResponseScripts.Add("ChatAjax()");
}
I'm certainly overlooking something outrageously stupid, but a fresh set of eyes from a seasoned ASP.Net Ajaxer would be really appreciated! Thanks in advance.
Clarification of Issue
What DOES work:
- The code runs properly.
- The JSON method is passed to the code behind and read.
- The CreateChatBox() method runs through and allegedly populates the literals and controls.
- All callbacks in the JSON chain are executed successfully.
What DOES NOT work:
- The UpdatePanel, even after the redundant postback, does not have this new HTML after code executes successfully.
回答1:
To Whom It May Concern
Well I happened to solve this problem the day after posting it. Of course there are now new hurdles to tackle but I am happy to say that my asynchronous chat module is nearly done. Since nobody decided to take on the problem, I am going to post what I did to properly produce dynamic, asynchronous objects based on hard-coded HTML in ASP.NET since, while Googling the matter, this post was the only relevant result popping up.
I'll start by saying I am well aware that this is a very unconventional approach. That being said, the requirements of the project justified the means. While there may be many other ways to accomplish your goal, this does work. I am not going to go into extraneous details with respect to my particular project, but hopefully this will help somebody in the future.
The Wrongs
The primary problem with my original question was the way I was attacking the rendering sequence. A major flaw in my logic was attempting to separate the ASP controls (literals, placeholders, buttons and such) from my HTML too much. My initial approach (from above) looked like this:
<asp:UpdatePanel ID="Panel3" runat="server" OnLoad="Panel3_Load" UpdateMode="Conditional">
<ContentTemplate>
<asp:Literal ID="ChatBoxesLiteralTop" runat="server" />
<asp:Literal ID="ChatBoxesLiteralMid" runat="server" />
<asp:PlaceHolder ID="ChatBoxesPlaceHolder" runat="server" />
<asp:Literal ID="ChatBoxesLiteralBot" runat="server" />
<div id="UserListCorner">
<img id="UserListBtn" src="images/list.png" />
</div>
<div id="UserList" class="UserListHidden">
<div id="UserListView">
<asp:Literal ID="UserListViewLiteral" runat="server" />
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
The final result looks more like this:
<asp:UpdatePanel ID="Panel3" runat="server" OnLoad="Panel3_Load" UpdateMode="Conditional">
<ContentTemplate>
<asp:PlaceHolder ID="ChatBoxesPlaceHolder" runat="server" />
<div id="UserListCorner">
<img id="UserListBtn" src="images/list.png" />
</div>
<div id="UserList" class="UserListHidden">
<div id="UserListView">
<asp:Literal ID="UserListViewLiteral" runat="server" />
</div>
</div>
<asp:Label ID="Label42" Font-Bold="true" runat="server" />
<asp:HiddenField runat="server" ID="LatestDisplayTick" />
</ContentTemplate>
</asp:UpdatePanel>
With the code behind (abridged) similar to this:
Literal top = new Literal();
// ...
UpdatePanel UpdatePanel2 = new UpdatePanel();
// ...
top.Text = @"<div id='ChatBox' class='ChatBoxShown'>
<div class='ChatBoxHeader'>
<img id='ChatBoxStatusBtn' src='Images/status-online.png' />
<span id='ChatBoxUserLabel'>" + UserNames[0] + @"</span>
<img id='closeBtn' src='Images/close.png' />
<img id='toggleTab' src='Images/up-arrow.png' />
</div>";
top.ID = "ChatBoxesLiteralTop";
top.Mode = LiteralMode.PassThrough;
// ...
UpdatePanel2.ID = "UpdatePanel2";
UpdatePanel2.UpdateMode = UpdatePanelUpdateMode.Conditional;
UpdatePanel2.ChildrenAsTriggers = false;
UpdatePanel2.ContentTemplateContainer.Controls.Add(top2);
// ...
Panel3.ContentTemplateContainer.Controls.Add(top);
Panel3.ContentTemplateContainer.Controls.Add(UpdatePanel2);
Panel3.ContentTemplateContainer.Controls.Add(mid);
What It Means
All I've done is wrapped the entirety of my chatbox elements inside a single placeholder, dynamically creating HTML elements that wrap ASP controls all from the server and posting it as a "chunk" of dynamic data. This sidesteps some strange behaviors with ASP control placement otherwise, and allows for a quasi-OO approach for the client-side functionality of my project. After creation, I can now make use of some JSON and AJAX calls to dynamically enter data into said dynamically created controls.
An example would be posting a message received from a database notification to my chat window (ChatBoxesLiteralMid control) when it is received.
After Page/Control Load
if(ChatBoxesLiteralMid != null)
ChatBoxesLiteralMid.Text += @"<div class='ChatBoxEntry'><span class='ChatBoxEntryName ChatBoxSelf'>" + AppParameters.Current.AppUser.FirstName + "</span>: <span class='ChatBoxEntryMessage'>" + dy.Rows[dy.Rows.Count - 1]["Message"].ToString() + "</span></div>";
Why Go To The Trouble?
What I have accomplished is for a particular project with needs to go far above and beyond the original scope, started by another developer years prior. This is an unconventional way to teach the old dog some new tricks. I now have near-full control of an indiscriminate amount of real-time chat boxes/sessions on the CLIENT side. It's really pretty freakin' sweet honestly. Please feel free to post questions (or concerns) as I regularly check SO and am happy to respond.
来源:https://stackoverflow.com/questions/15572735/asp-net-ajax-updatepanel-dynamic-html-insertion-issue-telerik