I am trying to create a custom component. The component should by dynamically initialized in code behind. The component presents a custom Window containing other components, like datefields, dropdown fields etc. I derived my class from Ext.Net.Window and added simple DateField. The date should than be used by a button click on the server (Date should not be passed over DirectMethod parameter). When I add this component to mark-up it works perfectly. But when I add the window in code behind, the value of the datefield is not set after the server call.
I am creating the window in the life cycle in OnInit event by "Controls.Add(mywindow)". It would be great if anybody could give me a hint. Here my window code (onExecuteButtonClick just calls the direct method and hides the window):
public sealed class WindowFilterComponent:Window
{
private const string Script = "MyProject.JavaScript.src.WindowFilterComponent.js";
public override string InstanceOf
{
get
{
return "MyProject.Filter.WindowFilterComponent";
}
}
public override string XType
{
get
{
return "windowfiltercomponent";
}
}
private Button _btnExecute;
private Button _btnCancel;
private DateField _dateField;
protected override void OnInit(EventArgs e)
{
AutoHeight = true;
_btnExecute = new Button("Execute Export");
_btnExecute.Listeners.Click.Handler = string.Format("#{{{0}}}.onExecuteButtonClick()", ID);
_btnCancel = new Button("Cancel");
_btnCancel.Listeners.Click.Handler = string.Format("#{{{0}}}.onCancelButtonClick()", ID);
Buttons.Add(_btnExecute);
Buttons.Add(_btnCancel);
_dateField = new DateField();
Items.Add(_dateField);
base.OnInit(e);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (ExtNet.IsAjaxRequest || Page.IsCallback) return;
ResourceManager.GetInstance().AddDirectMethodControl(this);
}
[DirectMethod(ShowMask = true)]
public void ExecuteClick()
{
var date = _dateField.SelectedValue;
}
}
Now the useage in my page in the OnInit event:
protected override void OnInit(EventArgs e)
{
var myWindow = new WindowFilterComponent()
{
Hidden = false,
Width = 500
};
myWindow.ID = myWindow.ID + "MyComponent";
Controls.Add(myWindow);
base.OnInit(e);
}
I think the Window is rendered outside of the Form.
Please replace
Controls.Add(myWindow);
with
Form.Controls.Add(myWindow);
Also I would recommend to set up explicit IDs for the submittable fields (the DateField in your case) to ensure that the id key from POST data will match the control's ID on the server.
Related
I'm developing custom controls with security included. When the user does not have access to the control, the control makes itself disable but also go invisible. The control is not rendered and it does not appear on the page. At this point, everything is fine.
My question is how I can secure the control the prevent user to change the value?
I have injected an input in my form with Chrome HTML Inspector because like it should be, the field is not rendered, when I submit the form with the injected input with a new value, the server has the new value in the control value property.
public enum UserRole {
Standard,
Administrator,
[...]
}
//For this example, my custom control is derived from HtmlInputText. [ToolboxData("<{0}:MyCustomControl runat=\"server\"></{0}:MyCustomControl>")]
public class MyCustomControl: System.Web.UI.HtmlControls.HtmlInputText
{
public UserRole? MinimumRoleRequired { get; set; }
protected override void OnLoad(EventArgs e)
{
//Simplified version
if (this.Page.CurrentUser.Role < this.MinimumRoleRequired)
{
this.Visible = false;
this.Disabled = true;
return;
}
[...]
}
protected override void Render(HtmlTextWriter writer)
{
if (!this.Visible || this.Disabled)
{
return;
}
[...]
}
[...]
}
//My page who contain the control:
//HTML (MyPage.aspx)
<Controls:MyCustomControl ID="tbAdminOnly"runat="server"></Controls:MyCustomControl>
//C# (MyPage.aspx.cs)
public partial class UserEdit : Page
{
protected override void OnInit(EventArgs e)
{
this.tbAdminOnly.MinimumRoleRequired = UserRole.Administrator;
[...]
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (this.IsPostBack)
{
string postBackValue = tbAdminOnly.Value;
return;
}
tbAdminOnly.Value = "Hello world!";
}
}
When I load the page as a standard user, the control is not rendered. But if I inject input in the html page
//Note, i need to know the valid name/id but it could be done.
<input type="text" name="tbAdminOnly" id="tbAdminOnly" value="Damn shit">
The postBackValue is now the new value from the injected input. How I can prevent that?
Thanks.
To prevent user from injecting html controls, you need to sanitize the inputs. There are similar posts. How to use C# to sanitize input on an html page?
I need to access the controls created by CreateChildControls() from another class, so that when I choose the file I have the path on a string to refer to.
I have tried the solutions in Accessing controls created dynamically (c#) and Problem in accessing dynamically created controls But with no joy thanks
publicTextBox txtUrl;
protected override void CreateChildControls()
{
Label lblUrl = new Label();
lblUrl.ID = "lblUrl";
lblUrl.Text = "Url: ";
Controls.Add(lblUrl);
TextBox txtUrl = new TextBox();
txtUrl.ID = "txtUrl";
Controls.Add(txtUrl);
AssetUrlSelector picker = new AssetUrlSelector();
picker.ID = "ausUrl";
picker.DefaultOpenLocationUrl = OpenUrl;
picker.AssetUrlClientID = txtUrl.ClientID;
picker.AssetUrlTextBoxVisible = false;
Controls.Add(picker);
Control control = Page.LoadControl(_ascxPath);
Controls.Add(control);
}
From another class I should be able to access the textbox
protected void Button1_Click(object sender, EventArgs e)
{
AssetPicker asspi = new AssetPicker();
string aaa = asspi.txtUrl.Text;
}
I had to make the controls public to be accessible from another class. but it retuns null reference error. I have updated the initial post
If you expose your child controls publicly, you need to call EnsureChildControls in the getter for each publicly-exposed child control. This will force CreateChildControls to be executed, and hence your control tree to be built, ensuring the caller does not get a null reference.
E.g.:
public Button MyChildButton
{
get
{
EnsureChildControls();
return _myChildButton;
}
}
private Button _myChildButton;
...
protected override void CreateChildControls()
{
...
_myChildButton = new Button();
...
}
Note that in order to do this, you need to expose your child controls as properties, not fields. I.e. in your sample code, you need to replace:
public TextBox txtUrl;
by:
public TextBox TxtUrl
{
get
{
EnsureChildControls();
return txtUrl;
}
}
private TextBox txtUrl;
You should also inherit from CompositeControl, which does something similar for the Controls property:
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return base.Controls;
}
}
If for some reason you are not inheriting from CompositeControl, then you'll need to add this Controls override to your class.
Incidentally, exposing child controls might be giving too much information to your callers, who probably shouldn't be concerned with such implementation details. Instead you could expose only the relevant properties of your child controls. For example, instead of exposing a child TextBox TxtUrl, you could expose a string property Url thus:
public string Url
{
get
{
EnsureChildControls();
return txtUrl.Text;
}
set
{
EnsureChildControls();
txtUrl.Text = value;
}
}
At the end, what .NET does when you add a static control to a page, it will hold a reference as of the control as a field (they usually go to the .designer file). So, just put the controls as fields in the same fashion:
private Label lblUrl;
private TextBox txtUrl;
private AssetUrlSelector picker;
private Control control;
protected override void CreateChildControls()
{
lblUrl = new Label();
lblUrl.ID = "lblUrl";
lblUrl.Text = "Url: ";
Controls.Add(lblUrl);
txtUrl = new TextBox();
txtUrl.ID = "txtUrl";
Controls.Add(txtUrl);
picker = new AssetUrlSelector();
picker.ID = "ausUrl";
picker.DefaultOpenLocationUrl = OpenUrl;
picker.AssetUrlClientID = txtUrl.ClientID;
picker.AssetUrlTextBoxVisible = false;
Controls.Add(picker);
control = Page.LoadControl(_ascxPath);
Controls.Add(control);
}
My asp.net application has a custom base user control that is inherited from other user controls. This custom base user control has three properties that have been made public. When the user control is loaded the custom base user control properties are null. I am trying to figure what I am doing wrong. can someone please help figure out what step I am missing?
custom base user control loading code from parent page:
private void Render_Modules()
{
foreach (OnlineSystemPageCustom.OnlineSystemPageHdr.OnlineSystemPageModule item in custompage.Header.Modules)
{
if (item.ModuleCustomOrder != 99)
{
webonlinecustombase ctl = (webonlinecustombase)Page.LoadControl("../IPAM_Controls/webtemplatecontrols/webonlinecustombase.ascx");
ctl.Event = Event;
ctl.custompage = custompage;
ctl.custommodule = item;
this.eventprogrammodules.Controls.Add(ctl);
}
}
}
custom base user control code behind
public partial class webonlinecustombase : System.Web.UI.UserControl
{
public Event Event { get; set; }
public OnlineSystemPageCustom custompage { get; set; }
public OnlineSystemPageCustom.OnlineSystemPageHdr.OnlineSystemPageModule custommodule { get; set; }
public void Page_Load(object sender, EventArgs e)
{
string typeName = custommodule.ModuleInternetFile;
inpagelink.HRef = "#" + custommodule.ModuleName.Replace(" ", "").Replace("/", "");
modtitle.InnerText = custommodule.ModuleName;
Type child = Type.GetType(typeName);
UserControl ctl = (UserControl)Page.LoadControl(child, null);
if (ctl != null)
{
this.modsection.Controls.Add(ctl);
}
}
}
sample code of user control inheriting base user control
public partial class eventscientificoverview : webonlinecustombase
{
protected void Page_Load(object sender, EventArgs e)
{
if (custommodule.ModuleDefaultVerbiage != null && custommodule.ModuleDefaultVerbiage != "") { this.Load_Verbiage(false); }
else if (custommodule.ModuleCustomVerbiage != null && custommodule.ModuleCustomVerbiage != "") { this.Load_Verbiage(true); }
}
protected void Load_Verbiage(bool usecustom)
{
if (usecustom) { this.scientificoverviewverbiage.InnerHtml = custommodule.ModuleCustomVerbiage; }
else { this.scientificoverviewverbiage.InnerHtml = custommodule.ModuleDefaultVerbiage; }
}
}
You must call Render_Modules in the init event of the parent page.
Also, you may want to restructure your base/custom classes to avoid event execution order confusion since the load event will be fired in both the base and the custom classes.
Any time we have this type of structure, we always implement an OnLoad method in the base class for inheritors to override. This way we can control exactly when the Load logic is executed in the inheritors.
Updated with additional info
Here is some additional information on how to handle the load events in base and child classes.
In webonlinecustombase, add the following:
protected virtual void OnPageLoad() {
}
then modify your page load event to call this new method at the appropriate time:
public void Page_Load(object sender, EventArgs e)
{
string typeName = custommodule.ModuleInternetFile;
inpagelink.HRef = "#" + custommodule.ModuleName.Replace(" ", "").Replace("/", "");
modtitle.InnerText = custommodule.ModuleName;
Type child = Type.GetType(typeName);
UserControl ctl = (UserControl)Page.LoadControl(child, null);
if (ctl != null)
{
this.modsection.Controls.Add(ctl);
}
// Now let the inheritors execute their code
OnPageLoad();
}
then, in your inherited class, change:
protected void Page_Load(object sender, EventArgs e)
to
protected override void OnPageLoad()
As I was reviewing this code, I discovered that you are also dynamically loading controls in webonlinecustombase. You will need to move the loading of the controls into the init event in order for them to work correctly in the standard page logic.
Did you try base.[PropertyName] ?
If you have a new keyword or override in your derived class and had only the values in your base class could be the culprit. This has happened to me before.
This question is for an ASP.NET guru. Its driving me nuts.
I have inherited an ASP.NET Web Forms application. This application uses a complex
structure of nested user controls. While complex, it does seem necessary in this case.
Regardless, I have a page that uses a single UserControl. We will call this UserControl
root control. This UserControl is defined as follows:
widget.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="widget.ascx.cs" Inherits="resources_userControls_widget" %>
<div>
<asp:Panel ID="bodyPanel" runat="server" />
</div>
widget.ascx.cs
public partial class resources_userControls_widget : System.Web.UI.UserControl
{
private string source = string.Empty;
public string Source
{
get { return source; }
set { source = value; }
}
private string parameter1 = string.Empty;
public string Parameter1
{
get { return parameter1; }
set { parameter1 = value; }
}
private DataTable records = new DataTable();
public DataTable Records
{
get { return records; }
set { records = value; }
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
UserControl userControl = LoadControl(source) as UserControl;
if (parameter1.Length > 0)
userControl.Attributes.Add("parameter1", parameter1);
bodyPanel.Controls.Add(userControl);
}
private void InsertUserControl(string filename)
{
}
}
In my application, I am using widget.ascx in the following way:
page.aspx
<uc:Widget ID="myWidget" runat="server" Source="/userControls/widgets/info.ascx" />
page.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
DataTable table = GetData();
myWidget.Records = table;
}
Please notice how info.ascx is set as the UserControl we want to load in this case. This approach is necessary in this case. I've removed the extraneous code that justifies it to focus on the problem. Regardless, in info.ascx.cs I have the following:
info.ascx.cs
protected void Page_Load(object sender, EventArgs e)
{
// Here's the problem
// this.Parent.Parent is a widget.ascx instance.
// However, I cannot access the Widget class. I want to be able to do this
// Widget widget = (Widget)(this.Parent.Parent);
// DataTable table = widget.Records;
}
I really need to get the value of the "Records" property from the Parent user control. Unfortunately, I can't seem to access the Widget class from my code-behind. Are there some rules about UserControl visibility at compile time that I'm not aware of? How do I access the Widget class from the code-behind of info.ascx.cs?
Thank you!
Firstly you need to create an interface and implement it to the Widget user control class.
For instance,
public interface IRecord
{
DataTable Records {get;set;}
}
public partial class resources_userControls_widget : System.Web.UI.UserControl, IRecord
{
...
}
And in code behind of Info.ascx.cs,
protected void Page_Load(object sender, EventArgs e)
{
// Here's the problem
// this.Parent.Parent is a widget.ascx instance.
// However, I cannot access the Widget class. I want to be able to do this
// Widget widget = (Widget)(this.Parent.Parent);
// DataTable table = widget.Records;
IRecord record=this.Parent.Parent;
DataTable table = widget.Records;
}
In your case, maybe better to use some server object's like ViewState or Session. Fill it within DataTable on your page and get it in Page_load event handler on info.ascx user control.
I'm making one user control.
This user control is for to display advertisment from database.
Just we have to pass the place id and it will fetch the record from database and display on specific page.
It's working perfectly but when im draging this user control multiple time on same page then it doesn't work perfectly.
Means im passing different different place id for each usercontrol but both usercontrol takes only one place id and display same content in both usercontrol
Here is the code im using
public partial class Advertisment : System.Web.UI.UserControl
{
static int _Advertismentid;
#region Get Set Property
public int Placeid
{
get
{
return _Advertismentid;
}
set
{
_Advertismentid = value;
}
}
#endregion
#region Load Advertisment Function
public void FnLoadAdvetsiment()
{
DataTable dt = new cls_Advertisements().FnGetAdvertsimentContent(Convert.ToInt32(Placeid));
int i = 0;
DataView dv = new DataView();
if (dt.Rows.Count > Convert.ToInt32(Session["rowno"]))
{
i = Convert.ToInt32(Session["rowno"]);
ltrAdvertisment.Text = (dt.Rows[i]["Content"].ToString());
AdTimer.Interval = Convert.ToInt32(dt.Rows[i]["Timer"].ToString());
Session["rowno"] = Convert.ToInt32(Session["rowno"]) + 1;
}
else
{
Session["rowno"] = i = 0;
ltrAdvertisment.Text = dt.Rows[i]["Content"].ToString();
AdTimer.Interval = Convert.ToInt32(dt.Rows[i]["Timer"].ToString());
}
}
#endregion
#region Page Load Event
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
FnLoadAdvetsiment();
if (Session["rowno"] == null)
{
Session["rowno"] = 0;
}
}
}
#endregion
#region Timer Tick Event
protected void Timer1_Tick(object sender, EventArgs e)
{
FnLoadAdvetsiment();
}
#endregion
}
I assume your problem is that both ads are displaying the same content.
Its likely this is because you are using the same sessions variables to store the data in. Try prefixing the session key with the id of the control or something else unique or even better try to not sure session at all if you can.
When you declare a variable as "static" then only a single instance of the variable is referenced across all different instances of your control class.
Effectively, the last value you set the "_Advertismentid" variable to will be the same value for all controls.
Declare your variable as;
int _Advertismentid;