I'm new to ASP.NET C# and trying to accomplish the following:
Have a Default.aspx page with two user controls (Control1.ascx and Control2.ascx)
Both user controls are within UpdatePanels.
Need the TextBox on the second user control disabled until the TextBox on the first control has been validated. Once validated, TextBox on user control2 needs to be enabled.
These user controls will be re-used on multiple pages.
Help is appreciated. If I need to post some code let me know.
Here's code sample:
Default.aspx
<%# Page Title="Home Page" Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%# Register src="Control1.ascx" tagname="CTL1" tagprefix="uc1" %>
<%# Register src="Control2.ascx" tagname="CTL2" tagprefix="uc2" %>
<uc1:CTL1 Id="CTL1" runat="Server" UpdateMode="Conditional"/>
<uc2:CTL2 Id="CTL2" runat="Server" UpdateMode="Conditional"/>
Default.aspx.cs
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
Control1.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="Control1.ascx.cs" Inherits="Control1" %>
<asp:UpdatePanel ID="UpdatePanel_Fld1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="TextBox_Fld1" runat="server" Enabled="True" ></asp:TextBox>
<asp:ImageButton ID="ImageButton_ValidateFld1" runat="server" ImageUrl="~/images/validate.jpg"
onclick="ImageButton_ValidateFld1_Click" />
<asp:Label ID="LabelFld1Summary" runat="server" > </asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
Control1.ascx.cs
public partial class Control1 : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public void ImageButton_ValidateFld1_Click(object sender, ImageClickEventArgs e)
{
LabelFld1Summary.Text = "Validated";
}
}
Control2.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="Control2.ascx.cs" Inherits="Control2" %>
<asp:UpdatePanel ID="UpdatePanel_Fld2" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="TextBox_Fld2" runat="server" Enabled="False"></asp:TextBox>
<asp:ImageButton ID="ImageButton_ValidateFld2" runat="server" ImageUrl="~/images/validate.jpg"
onclick="ImageButton_ValidateFld2_Click" />
<asp:Label ID="LabelFld2Summary" runat="server" > </asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
Control2.ascx.cs
public partial class Control2 : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public void ImageButton_ValidateFld2_Click(object sender, ImageClickEventArgs e)
{
LabelFld2Summary.Text = "Validated";
}
}
I suggest go with simple javascript or involve jQuery to do the enable/disable thing, add some js code into a client side validation script
I suggest getting your scenario working with synchronous postbacks first, then adding the updatepanels into the mix. As a rough sketch, in a server-side OnClick handler for some button or other you can set the enabledness of the second control based on the result of validation of the first control. Then, you just need to make sure you call Update() on Control2.ascx's UpdatePanel when the asynch postback targeting Control1.ascx's UpdatePanel happens.
That said, this is going to be mildly annoying from a user's perspective. Unless the first control modulates a great deal of UI below it (like, switching to a separate control set entirely), why not just let your users enter text into both fields and validate on the combination of them?
I agree with Simon. jQuery would probably be the easiest way to accomplish this. you can use jQuery's ajax methods to make calls to WebMethods if you need to interact with the code behind for any reason.
I've used update panels and the ICallbackEventHandler interface (http://madskristensen.net/post/Asynchronous-GridView-in-5-simple-steps.aspx is a good example of its use) with some success.
While I tend to stay away from UpdatePanels, I realized that they use the ICallbackEventHandler interface behind the scenes and I probably make more work for myself. The only benefit of doing it the way I did is that I don't have a bunch of garbage sitting in my ViewState (UpdatePanels love ViewState), as I've persisted it in the server-side session state.
In my case, the reason for going with the ICallbackEventHandler method over using jQuery's ajax calls and WebMethods in the code behind was that I wanted to have access to non-static fields (including my web controls). Turns out I needed to manually persist the data displayed on the page in session or otherwise and probably ended up making more work for myself in the end. It was a good chance to learn something new, but the benefits I gained from having access to the pages controls were minimal/non-existent.
Related
I have a AjaxFileUpload control in a usercontrol which is loaded dynamicaly on Postback, the problem here is, once the file is uploaded IsPostBack is false due to which the usercontrol is not loaded, causing the OnUploadCompleteAll event to not be triggered.
I found out that AjaxFileUpload control has its own postback property AjaxFileUpload.IsInFileUploadPostBack, how do i access this property from my main WebForm1.aspx page?
When an event is triggered from AjaxFileUpload i would like to check IsInFileUploadPostBack on page load of WebForm1.aspx and then load the usercontrol.
here is the code.
WebForm1.aspx
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:Button ID="Button1" runat="server" Text="Load Control" OnClick="Button1_Click" />
<asp:PlaceHolder ID="Placeholder1" runat="server" />
</form>
Codebehind
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
loadcontrol();
}
protected void Button1_Click(object sender, EventArgs e)
{
}
private void loadcontrol()
{
this.Placeholder1.Controls.Clear();
var _controls = LoadControl("~/WebUserControl1.ascx");
this.Placeholder1.Controls.Add(_controls);
}
WebUserControl1.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs" Inherits="AjaxFileUpload_Test.WebUserControl1" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<div id="div1">
<ajaxToolkit:AjaxFileUpload ID="AjaxFileUpload1" UseAbsoluteHandlerPath="false" OnUploadCompleteAll="AjaxFileUpload1_UploadCompleteAll" OnUploadStart="AjaxFileUpload1_UploadStart" runat="server" />
</div>
Is there any specific reason you are loading the usercontrol from codebehind?
An ajax control does not create an actual postback which is why that is always false. For what you seem to want you should use a NON-ajax file upload.
Got it working !!
Since i have to load the controls only then will i be able to access AjaxFileUpload.IsInFileUploadPostBack property, i decided to take an unorthodox approach.
Added below code to Page_Init
//to load the controls if AsyncFileUpload causes a postback
//the URL should contain the ID of the control in its context query string
if (Request.HttpMethod.Contains("POST") && Request.Url.AbsoluteUri.Contains("AjaxFileUpload1"))
loadcontrol();
I have 5 files.
Default.aspx
Search.ascx
SearchSQL.ascx
Grid.ascx
GridSQL.ascx
I have registered the ascx files in the default.aspx page and use properties to expose the controls to the default page. And that works great.
My issue is how do I send data back and fourth between the different ascx pages? If I register on any of those it will give me a Circular file reference error.
Using public properties, I have the Search.ascx registered on the GridSQL.ascx to pass the search parameters into Gridsql string, and then the GridSQL.ascx on the Grid.ascx file to pass the sql string to the grid databind.
There has got to be a much easier way to pass data BACK & FOURTH between pages, or am I wrong? When you try to register on the other page to pass data back to the page that sent it, you get the circular file reference error. I have heard a few resolutions like changing file structure, which I have tried, and also about Batch, but that kills performance. Believe i have spent days trying to find resolutions on this. I was going to comment on some questions but Stack does not allow me until I have 50 Rep.
My company is requiring us to use all separate files from now on and I just cant believe this is the best way to communicate between user controls.
Proper way is you want to bubble up the child control's event to parent.
Then let parent to forward the event to other controls.
Note: Here is the demo. You might want to rename delegates and methods which make sense to your scenario.
Search (User Control which fires the event)
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="Search.ascx.cs" Inherits="DemoWebForm.Search" %>
<asp:TextBox runat="server" ID="SearchTextBox" />
<asp:Button runat="server" ID="SearchButton"
Text="Search" OnClick="SearchButton_Click" />
public delegate void MessageHandler(string searchText);
public partial class Search : System.Web.UI.UserControl
{
public event MessageHandler SearchText;
protected void SearchButton_Click(object sender, EventArgs e)
{
SearchText(SearchTextBox.Text);
}
}
GridSql (User Control)
Finally, GridSql.ascx receives the search text.
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="GridSql.ascx.cs" Inherits="DemoWebForm.GridSql" %>
<asp:Label runat="server" ID="SearchTextLabel"/>
public partial class GridSql : System.Web.UI.UserControl
{
public void SearchTextMethod(string searchText)
{
SearchTextLabel.Text = searchText;
}
}
Parent
<%# Page Language="C#" AutoEventWireup="true"
CodeBehind="Parent.aspx.cs" Inherits="DemoWebForm.Parent" %>
<%# Register src="~/Search.ascx" tagname="Search" tagprefix="uc1" %>
<%# Register src="~/GridSql.ascx" tagname="GridSql" tagprefix="uc2" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<uc1:Search ID="Search1" runat="server" />
<uc2:GridSql ID="GridSql1" runat="server" />
</form>
</body>
</html>
public partial class Parent : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Search1.SearchText += m => GridSql1.SearchTextMethod(m);
}
}
I have simple web user control (the code I found somewhere in the web):
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs"
Inherits="ARP.DynamicsCRM2011.MagicWebForm.WebUserControl1" %>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="True" OnCheckedChanged="CheckBox1_CheckedChanged"
Text="Checkbox" />
<asp:Button ID="Button1" runat="server" Text="Button" Visible="False" OnClick="Button1_Click" />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
protected void Page_Load(object sender, EventArgs e)
{
}
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
Button1.Visible = CheckBox1.Checked;
}
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToString();
}
Now I want to add this control to my page (programmatically in OnLoadComplete event):
<%# Reference Control="~/WebUserControl1.ascx" %>
WebUserControl1 myControl = (WebUserControl1)Page.LoadControl("~/WebUserControl1.ascx");
myControl.ID = "myControl_" + some_name;
parentControl.Controls.Add(myControl);
Of course I have SriptManager on the page and my control is added properly. I know that programmatically added controls must be recreated every time the page is loaded. Unfortunately this causes creating new control, so checking checkbox doesn't work - after checking it the OnLoadComplete (of the page) is fired again and new control is created. If I omit that then nothing is displayed. So the question is - how to do this?
Dynamic control should be re-added to the control tree OnPreInit, see documentation:
PreInit - Create or re-create dynamic controls.
ASP.NET Page Life Cycle Overview
You can add that control on button click and save count of added controls in some storage like Session. The in Page_Init you need to check that count value and recreate each control you have add before.
I have a master page that contains an image as follow:
<asp:Image ID="imgCompanyLogo" runat="server" ImageUrl="image path" />
and in a child page I want to edit the property ImageUrl as follow:
Image imgCompanyLogo = (Image)Page.Master.FindControl("imgCompanyLogo");
imgCompanyLogo.ImageUrl = ResolveUrl("~/images/CompanyLogo/Logo.png");
and it doesn't give me an exception, but it doesn't change anything.
Note: I have an UpdatePanel in the child page.
Since the image is sitting outside of the UpdatePanel, server side changes will not be executed on the image after a partial postback. Your only option is to inject JavaScript into the page and change the image URL.
Use the ScriptManager.RegisterStartupScript Method to inject JavaScript after the partial postback.
Something like the following will work for you:
C#
protected void btnPostback_Click(object sender, EventArgs e)
{
imgCompanyLogo.ImageUrl = ResolveUrl("~/images/CompanyLogo/Logo.png");
ScriptManager.RegisterStartupScript(btnPostback,this.GetType(), "myScript", "ChangeImage('" + ImageUrl + "');",false);
}
JavaScript
function ChangeImage(imgURL) {
//make sure the ID of the image is set correctly
document.getElementById('imgCompanyLogo').src = imgURL;
}
Wrap image by UpdatePanel with UpdateMode="Always"
Master Page:
<asp:UpdatePanel runat="server" UpdateMode="Always">
<ContentTemplate>
<asp:Image runat="server" ID="Image1" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:ContentPlaceHolder ID="MainContent" runat="server">
</asp:ContentPlaceHolder>
public void SetImageUrl(string url)
{
Image1.ImageUrl = url;
}
Child Page:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Button Text="Click Me" runat="server" OnClick="UpdateImage" />
</ContentTemplate>
</asp:UpdatePanel>
protected void UpdateImage(object sender, EventArgs e)
{
((Main)Master).SetImageUrl("~/Images/0306d95.jpg");
}
The code above works well for me.
Have a look at Sys.WebForms.PageRequestManager Class. Define handler in javascript and may change the image source.
If your code is being run after an async postback (per your UpdatePanel) then changes to anything outside the UpdatePanel will not be rendered. Content in the master page would definitely seem to qualify.
If this is what you're trying to do, this model won't really work. You will need to use some client script to effect changes to already-rendered content when working with this model.
An UpdatePanel is a construct to identify an area that's updated through ajax. The page is not actually reloaded. So an postback can never change content that's outside of the UpdatePanel (or control bound to that panel) that sourced it.
Here's a basic implementation (using jQuery). Add a hidden field to pass the new source to the client. This must be inside the UpdatePanel. Change this value from the server when you want the image to update with new_image_src.Value=ResolveUrl(...);
<asp:HiddenField ClientIdMode="Static" runat="server" id="new_image_src"
value="" EnableViewState="false">
Give your image a static id too to make life easier:
<asp:Image ClientIdMode="Static" runat="server" id="dynamic_image" ImageUrl="..." >
Add javascript to the page (should NOT be in the UpdatePanel):
function updateImage() {
var new_src=$('#new_image_src');
if (new_src) {
$('#dynamic_image').attr('src',new_src);
/// erase it - so it won't try to update on subsequent refreshes
new_src.val('');
}
}
$(document).ready(function() {
/// adds an event handler after page is refreshed from asp.net
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(updateImage);
});
This wouldn't be difficult to do without jquery either but seems more common than not these days.
I need to display a control consistently across a set of pages. So I'm using a MasterPage to do that in ASP.NET/C#. However I also need to programmatically access this control, mostly provide options to view/hide depending on whether the controls checkbox is clicked.
Here is the Source for the MasterPage
<div id="verifyInitial" runat="server">
<asp:CheckBox ID="chkInitialVerify" runat="server"
oncheckedchanged="chkInitialVerify_CheckedChanged" />
I agree that my initial data is correct.
</div>
<div id="verifyContinuous" runat="server">
<asp:CheckBox ID="chkContinuousVerify" runat="server"
oncheckedchanged="chkContinuousVerify_CheckedChanged" />
I agree that my continuous data is correct
</div>
Now in the code behind I want to perform the following operations. Basically if a person clicks on the checkbox for the initial div box, then the initial box disappears and the continous box shows up. However it seems that the code behind for the MasterPage does not activate whenver I click on the checkbox. Is that just the way MasterPages are designed? I always thought you could do add some sort of control functionality beyond utilizing the Page Load on the Master Page.
protected void chkInitialVerify_CheckedChanged(object sender, EventArgs e)
{
verifyContinuous.Visible = true;
verifyInitial.Visible = false;
}
protected void chkContinuousVerify_CheckedChanged(object sender, EventArgs e)
{
verifyContinuous.Visible = false;
}
If you're expecting the two controls to trigger a change for that page immediately then you'll need to set the AutoPostBack property to true for both of them:
<div id="verifyInitial" runat="server">
<asp:CheckBox ID="chkInitialVerify" runat="server" oncheckedchanged="chkInitialVerify_CheckedChanged" AutoPostBack="true" />
I agree that my initial data is correct.
</div>
<div id="verifyContinuous" runat="server">
<asp:CheckBox ID="chkContinuousVerify" runat="server" oncheckedchanged="chkContinuousVerify_CheckedChanged" AutoPostBack="true" />
I agree that my continuous data is correct
</div>
Otherwise, you need an <asp:button /> or some other control on the page to trigger a postback and cause your event handlers to run. The button, or other control, can either be on your masterpage or on your content page, the choice is entirely yours.