why my custom server control does not maintain the viewstate information? - c#

i'm creating a custom server control. here is the related piece of custom control:
public class ManagementUserControl : UserControl
{
GridView _grv;
public ManagementUserControl()
{
_grv = new GridView();
}
/// <summary>
/// binds the grid to controls.
/// </summary>
public override void DataBind()
{
_grv.DataBind();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!IsPostBack)
{
//add controls only when is not postback
InitializeGrid();
}
}
void InitializeGrid()
{
this.Controls.Add(_grv);
}
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public object DataSource
{
get { return _grv.DataSource; }
set { _grv.DataSource = value; }
}
}
i'm adding the datasource object in code behind of Default.aspx like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<string> lst = new List<string>();
lst.Add("test1");
lst.Add("test2");
lst.Add("test3");
ucManagement.DataSource = lst;
ucManagement.DataBind();
}
}
first, it works fine but when i postback the page the control is disapeared. so i checked the Conrols collection in Load event and saw that it's empty. worse than that is that grid.DataSource is null on postback!!
why the viewstate of the gridview is not maintained and the datasource value is lost on postback? by the way the viewstate is not turned off anywhere in page or web.config file.

found this on the asp.net site. seems to be your exact scenario.

Related

Properties of Webusercontrols

I have a question and I can not find the right terms to do a reasoned search and solve the question.
Let's see, when I'm creating a page, at some point I need to create a WebUserControl and defer something like state = "true" (like the text of the lables) inside the html tag so that as soon as the page loads , Whether or not that control is subsequently edited in code.
<MyControls:Teste Id="aaa" runat="server" state="false"/>
The test control code is as follows: (The HTML page of this control is blank, it only has the header)
public partial class WebUserControls_WUC_Tect : System.Web.UI.UserControl
{
private static bool state ;
public bool State
{
get { return state ; }
set { state = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
Problem:
Whenever the page returns to the server and is reloaded, the state variable is always set to false or true depending on the initial state I passed, what I intended was for this variable to be loaded only once at the beginning of the page and then Could only be changed by codebeind.
I am grateful for your suggestions.
greetings
Patrick Veiga
You need to use the ViewState to store the property value to keep the persistent value saved.
public partial class WebUserControls_WUC_Tect : System.Web.UI.UserControl
{
private static bool state ;
public bool State
{
get
{
if (ViewState["MyState"] == null)
{
ViewState["MyState"] = false;
}
return (bool)ViewState["MyState"];
}
set
{
ViewState["MyState"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
}

Custom Ext.Net component dynamically initialization

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.

accessing controls created by CreateChildControls()

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);
}

Accessing usercontrols in code-behind in ASP.NET

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.

Web Controls within UserControl null?

I've built a small User Control which is essentially a DropDownList with some preset Values based on what the Target-Property is set on.
Here's the Code:
public partial class Selector : System.Web.UI.UserControl
{
public string SelectedValue { get {return this.ddl.SelectedValue; } }
public int SelectedIndex { get { return this.ddl.SelectedIndex; } }
public ListItem SelectedItem { get { return this.ddl.SelectedItem; } }
private string target;
public string Target { get { return this.target; } set { this.target = value; } }
protected void Page_Load(object sender, EventArgs e)
{
ddl.DataSource = target=="Group"?Util.GetAllGroups(Session["sessionId"].ToString()):Util.GetAllUsers(Session["sessionId"].ToString());
ddl.DataBind();
}
}
ASP-Markup:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Selector.ascx.cs" Inherits="InspireClient.CustomControls.Selector" %>
<asp:DropDownList runat="server" ID="ddl">
</asp:DropDownList>
If I insert my Selector into an aspx-Page it works just fine.
Example:
<SCL:Selector Target="Group" runat="server" />
However, If I programmatically add it like this
ctrl = new Selector();
ctrl.Target = "User";
the DropDownList "ddl" is null and the application (logically) throws an error. Is Page_Load the wrong Method to do such a thing? What am I doing wrong?
I should add, "ctrl" is of type dynamic, not sure if this has anything to do with it.
Thanks in advance!
Dennis
Since you're dynamically adding a user control and not a "simple" web control, you should use the LoadControl() method to instantiate it:
protected void Page_Load(object sender, EventArgs e)
{
Selector yourControl = (Selector) LoadControl("Selector.ascx");
yourControl.Target = "User";
Controls.Add(yourControl);
}

Categories