How to update user control in UpdatePanel? - asp.net

I want to refresh a user control in UpdatePanel, but I would also like to refresh it with different property values.
<asp:UpdatePanel runat=server ID=up1>
<Triggers>
<asp:AsyncPostBackTrigger controlid="but01" eventname="Click" />
</Triggers>
<ContentTemplate>
<asp:Button runat="server" Text="Test" ID="but01" />
<UC:Uc runat=server ID="Uc1" />
</ContentTemplate>
</asp:UpdatePanel>
Codebehind for but01 click is
void but01_Click(object sender, EventArgs e)
{
this.Uc1.ID = 1;
this.Uc1.Length = 50;
}
I tested this code, and the user control is being refreshed, but new values ID=1, Length=50 are not applied.
Control code behind is rather simple
namespace Admin.Web.Controls
{
public partial class Uc1 : System.Web.UI.UserControl
{
private string p_to;
private string p_from;
private string p_subject;
private string p_body;
private string p_priority;
}
protected void Page_Load(object sender, EventArgs e)
{
this.txtFrom.Text = p_from;
this.txtTo.Text = p_to;
this.txtSubject.Text = p_subject;
this.txtBody.Text = p_body;
}
public string Subject
{
get
{
return p_subject;
}
set
{
p_subject = value;
}
}
public string From
{
get
{
return p_from;
}
set
{
p_from = value;
}
}
public string To
{
get
{
return p_to;
}
set
{
p_to = value;
}
}
public string Body
{
get
{
return p_body;
}
set
{
p_body = value;
}
}
}
ascx header is
<%# Control Language="c#" Inherits="Admin.Web.Controls.Uc1" AutoEventWireup="true" Codebehind="Uc1.ascx.cs" %>
When I initiate user control from aspx page during page load, everything is ok. On postback from control panel, user control is refreshed (checked with Label + time), but no values are passed to user control.

Remove Triggers tag
http://msdn.microsoft.com/en-us/library/Bb399001(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
OR
Move asp:Button to outside of UpdatePanel.
http://msdn.microsoft.com/en-us/library/Bb399001(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-5
Update:
Please make the setter and getter of the control as -
public string Subject
{
get { return txtSubject.Text; }
set { txtSubject.Text = value; }
}

Related

Setting label is always one step behind

I have the following code. I am trying to display a message when a file is to big. My problem is that the message is displayed only when I press the submit button twice. It is always one step behind. How can i fix that?
What I am doing is save a viewstate when the file is to big, and when the page loads, set the visibility of the label to true or false, depending on the file size.
I am guessing the load happens before my check, so is there another method i can use instead of Page_Load or can I do something else to make it work?
<asp:UpdatePanel ID="updatePanel" runat="server">
<ContentTemplate>
<div>
<div class="balClear">
<asp:FileUpload ID="uploader" CssClass="balUploader" runat="server"/>
<asp:ImageButton ID="uploaderEraser" CssClass="balUploaderCleaner" OnClick="uploaderEraser_Click" runat="server" Width="25" Height="25" />
</div>
<div style="clear:both">
<asp:Label ID="fileSizeError" runat="server" ForeColor="Red">The file you are trying to upload is too big. The maximul file size is 2MB.</asp:Label>
</div>
</div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="uploaderEraser" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
<asp:Button ID="submit" runat="server" Text="Submit" OnClick="submit_Click" />
cs code:
string groupURL = "~/Uploads/Group/";
string privateURL = "~/Uploads/Private/";
int maximumMB = 2;
string folderURL
{
get { return IsGroup == true ? groupURL : privateURL; }
}
public bool IsGroup
{
get { return ViewState["balUploader_IsGroup"] == null ? false : (bool)ViewState["balUploader_IsGroup"]; }
set { ViewState["balUploader_IsGroup"] = value; }
}
bool FileTooBig
{
get { return ViewState["balUploader_FileTooBig"] == null ? false : (bool)ViewState["balUploader_FileTooBig"]; }
set { ViewState["balUploader_FileTooBig"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (FileTooBig == true)
{
fileSizeError.Visible = true;
}
else
{
fileSizeError.Visible = false;
}
}
public void StoreFile()
{
if (uploader.HasFile)
{
if (uploader.FileBytes.Length / 1024 / 1024 < maximumMB)
{
FileTooBig = false;
string fileName = Path.GetFileName(uploader.FileName);
uploader.SaveAs(Server.MapPath(folderURL) + fileName);
}
else
{
FileTooBig = true;
}
}
else
{
FileTooBig = false;
}
}
protected void submit_Click(object sender, EventArgs e)
{
StoreFile();
}
Basically, what is happening is that the submit_Click event is being fired after the Page_Load. That is due to the ASP.NET page life cycle.
The basic order of events is the following:
1 - Init
2 - Load (Page_Load is fired)
3 - Control Events (submit_Click is fired)
4 - Load Complete
5 - Pre_Render
6 - Render
You have two options here.
1 - Use the LoadComplete handler:
protected override void OnLoadComplete(EventArgs e)
{
base.OnLoadComplete(e);
//Label Logic here
}
2 - Use the OnPreRender:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
//Label Logic here
}

Handling events from dynamic controls NOT added on Page_Load?

I've read a few articles on here and the web that have informed me that I cannot simply add a new control dynamically to the page, wire it to a handler, and expect it to work.
The solution given each time is that the dynamic controls need to be added to the page on Init each time.
My problem is, my controls are NOT added to the page on init, they are added after ANOTHER postback.
the workflow is this:
Page Loads
User fills in a textbox, clicks a button
Page Posts back, creating dynamic link controls in the button_click event based on the input
User clicks one of those link controls to proceed to the next step.
so if this is the behavior I need to support, is there any way to do this? It has to happen in the button_click of step 2, because the dynamic controls are based on the input the user puts in step 2.
have I painted myself into a corner here? how else could I handle such a workflow?
After you dynamically create a link button, set a flag in your page's view state. On postback, re-create the link button if the flag is set in view state. Here's a demo:
Markup:
<asp:Button runat="server" ID="button1" OnClick="button_Click" Text="Create button A" CommandArgument="A" />
<asp:Button runat="server" ID="button2" OnClick="button_Click" Text="Create button B" CommandArgument="B" />
<asp:PlaceHolder runat="server" ID="placeHolder"></asp:PlaceHolder>
Code-behind:
public partial class Default : System.Web.UI.Page
{
private bool LinkButtonCreated
{
get { return ((bool?)this.ViewState["LinkButtonCreated"]).GetValueOrDefault(); }
set { this.ViewState["LinkButtonCreated"] = value; }
}
private string LinkButtonCommandArgument
{
get { return (string)this.ViewState["LinkButtonCommandArgument"]; }
set { this.ViewState["LinkButtonCommandArgument"] = value; }
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
if (this.LinkButtonCreated)
this.CreateLinkButton(this.LinkButtonCommandArgument);
}
protected void button_Click(object sender, EventArgs e)
{
if (!this.LinkButtonCreated)
{
string commandArgument = ((Button)sender).CommandArgument;
this.LinkButtonCreated = true;
this.LinkButtonCommandArgument = commandArgument;
this.CreateLinkButton(commandArgument);
}
}
private void CreateLinkButton(string commandArgument)
{
LinkButton linkButton =
new LinkButton
{
ID = "linkButton",
Text = "Click me",
CommandArgument = commandArgument,
};
linkButton.Click += this.linkButton_Click;
this.placeHolder.Controls.Add(linkButton);
}
private void linkButton_Click(object sender, EventArgs e)
{
LinkButton linkButton = (LinkButton)sender;
linkButton.Text = "I was clicked! Argument: " + linkButton.CommandArgument;
}
}

ASP CompositeControl & ScriptManager

I'm really new to the WebControl / CompositeControl world, and I have a small test class I am playing with. It's just a LinkButton that updates when clicked. Things work great when I leave it out of UpdatePanel. But when I try to run it inside I still get a full page POST response. How can I make this class work inside a UpdatePanel?
Here's the class:
public class Test2 : CompositeControl
{
private static readonly object testButtonEvent = new object();
public event EventHandler OnTestClick
{
add { Events.AddHandler(testButtonEvent, value); }
remove { Events.RemoveHandler(testButtonEvent, value); }
}
private LinkButton testLinkButton;
public virtual string testLinkButtonText
{
get
{
object o = ViewState["testLinkButtonText"];
return (o == null) ? String.Empty : (string)o;
}
set
{
if (value == null)
ViewState.Remove("testLinkButtonText");
else
ViewState["testLinkButtonText"] = value;
}
}
protected override void OnInit(EventArgs e)
{
/* This stuff makes it ajax friendly but stops the text rendering
EnsureChildControls();
ScriptManager ScMan = ScriptManager.GetCurrent(Page);
if (ScMan != null)
{
ScMan.RegisterAsyncPostBackControl(testLinkButton);
} */
base.OnInit(e);
}
protected override void CreateChildControls()
{
Controls.Clear();
testLinkButton = new LinkButton();
testLinkButton.Command += new CommandEventHandler(testClick);
testLinkButtonText = "Test ViewState Text";
Controls.Add(testLinkButton);
}
void testClick(object sender, CommandEventArgs e)
{
testLinkButtonText = "Updated Text On " + DateTime.Now.ToLongTimeString();
}
protected override void Render(HtmlTextWriter writer)
{
RenderContents(writer);
}
protected override void RenderContents(HtmlTextWriter writer)
{
EnsureChildControls();
testLinkButton.Text = testLinkButtonText;
testLinkButton.RenderControl(writer);
}
}
The code in OnInit() causes the control to post correctly, but I don't get the updated text for the LinkButton. It is still firing off the event - when I debug I can see it being called. What's the proper way to set this control up for use in a UpdatePanel?
Usage, just in case:
<asp:UpdatePanel runat="server" UpdateMode="Conditional">
<ContentTemplate>
<cc:Test2 ID="jqTest02" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
You have to give the button an ID property...this is used in the client-side javascript that drives the UpdatePanel. More specifically, it's listed in the list of controls to intercept and do async postbacks for.
testLinkButton.ID = "btn";

Custom TextBox with built-in Validator: server side validation not firing

I have a class that looks like this:
public class TextField : TextBox
{
public bool Required { get; set; }
RequiredFieldValidator _validator;
protected override void CreateChildControls()
{
base.CreateChildControls();
_validator = new RequiredFieldValidator();
_validator.ControlToValidate = this.ID;
if(Required)
Controls.Add(_validator);
}
public override void Render(HtmlTextWriter tw)
{
base.Render(tw);
if(Required)
_validator.RenderControl(tw);
}
}
This has been working for a while in a internal application where javascript is always enabled. I recently noticed that an upstream javascript error can prevent the validators from firing, so the server side validation should kick in... right? right?
So the Page.IsValid property always returns true (I even tried explicitly calling Page.Validate() before-hand).
After some digging, I found that the validator init method should add the validator to the page, but due to the way I'm building it up, I don't think this ever happens. Thus, client side validation works, but server side validation does not.
I've tried this:
protected override OnInit()
{
base.OnInit();
Page.Validators.Add(_validator); // <-- validator is null here
}
But of course the validator is null here (and sometimes it's not required so it shouldn't be added)... but OnInit() is really early for me to make those decisions (the Required property won't have been loaded from ViewState for example).
Ideas?
The CreateChildControls is basically for the controls that have childs. RequiredFieldValidator is like a sibling to TextBox.
Here is the code that works for me:
public class RequiredTextBox : TextBox
{
private RequiredFieldValidator _req;
private string _errorMessage;
public string ErrorMessage
{
get { return _errorMessage; }
set { _errorMessage = value; }
}
protected override void OnInit(EventArgs e)
{
_req = new RequiredFieldValidator();
_req.ControlToValidate = this.ID;
_req.ErrorMessage = _errorMessage;
Controls.Add(_req);
base.OnInit(e);
}
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
base.Render(writer);
_req.RenderControl(writer);
}
}
And here it the ASP.NET page behind:
protected void SubmitClick(object sender, EventArgs e)
{
if(Page.IsValid)
{
// do something
}
}
And here is the ASPX code:
<MyControl:RequiredTextBox runat="server" ErrorMessage="Name is required!" ID="txtName"></MyControl:RequiredTextBox>
<asp:Button ID="Btn_Submit" runat="server" Text="Submit" OnClick="SubmitClick" />
Validators have to inherit from BaseValidator.

Access Master Page Control

I am using a UserControl Which is present in the Master Page. I need to access a Master page control in the UserControl. I need your suggestions.
The Scenario is A label is present in the Master Page. Based upon selections in the usercontrol i need to modify the masterpage label. The UserControl is present in the Master page itself not in the content place holder.
Create a public method (or public property) in the master page to modify your label and in the UserControl you are able to call it, through the Page.master object:
YourMasterPageClass master = Page.master as YourMasterPageClass;
if(master != null)
{
master.YourEditMethod("hello");
}
Quick and Easy way is to create event in control and handle in master like this:
//Control aspx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="TestControl.ascx.cs"
Inherits="TestControl" %>
<div style="width:300px;border:2px groove blue;">
<asp:Button ID="btn1" runat="server" Text="One" onclick="btn_Click" />
<asp:Button ID="btn2" runat="server" Text="Two" onclick="btn_Click" />
<asp:Button ID="btn3" runat="server" Text="Three" onclick="btn_Click" />
<asp:Button ID="btn4" runat="server" Text="Four" onclick="btn_Click" />
</div>
//Control C#
namespace Controls
{
public partial class TestControl : System.Web.UI.UserControl
{
public delegate void UserChoice(TestEventArgs e);
public event UserChoice OnUserChoice;
protected void btn_Click(object sender, EventArgs e)
{
if (OnUserChoice != null)
OnUserChoice(new TestEventArgs(((Button)sender).Text));
}
}
public class TestEventArgs : EventArgs
{
private string _value;
public TestEventArgs(string str)
{
_value = str;
}
public string Message
{
get { return _value; }
}
}
}
//MasterPage Code
protected void Page_Load(object sender, EventArgs e)
{
test1.OnUserChoice += new
Controls.TestControl.UserChoice(test1_OnUserChoice);
}
void test1_OnUserChoice(ROMS.Intranet.Controls.TestEventArgs e)
{
MasterLabel.Text = e.Message;
}
MasterLabel is name of the label in master page.
test1 is the control in master page.

Resources