So i am currently adding a collection of usercontrols to a Panel Collection.
Here is that code
foreach (IssuePoll poll in issuePollList)
{
IssuePollsUC issuePoll = (IssuePollsUC)Page.LoadControl("~/UserControls/IssuePollsUC.ascx");
issuePoll.LoadPoll(poll, false, politician.PoliticianID);
pnlUnFinishedTest.Controls.Add(issuePoll);
}
I am trying to get those usercontrols so i can call a validate method and save method inside each of those controls. Here is the code i am using for that, but it is not working.
foreach (Control control in pnlUnFinishedTest.Controls)
{
IssuePollsUC issuePolls = (IssuePollsUC)control;
issuePolls.SavePollAnswer(appUser.User.PersonID);
}
I get an error message on the convert, it says
"Unable to cast object of type 'System.Web.UI.LiteralControl' to type 'UserControls.IssuePollsUC'"
EDIT: Looks like the problem lies in the fact that a Control cannot be convert into (User Control)
There are other controls in your panel other than your user control i.e. the literal that is causing the cast to fail. Try
foreach (Control control in pnlUnFinishedTest.Controls)
{
IssuePollsUC issuePolls = control as IssuePollsUC;
if(issuePolls != null)
{
issuePolls.SavePollAnswer(appUser.User.PersonID);
}
}
This will make it more type safe.
EDIT
Please note that you must add dynamic controls in the Page_Init event not Page_Load or anywhere else. I suspect your controls aren't even there - adding them not in Page_Init means that that they are not in ViewState and won't be present in any control collection.
Related
I create dynamically checkboxes all of them with assigned checkedChanged event, which on postback I recreate and everything is working except one thing;
I should save the value of checked checkboxes in a List . But it seems that on each postBack event (every time I check a checkbox) the elements of the list are lost although myche is a global variable of type List ;
lblProba.Text +="in if clause; element count="+ myche.Count.ToString();
gives me 1 every time I check a checkbox
protected void checkChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
if (chk.Checked)
{
myche.Add(chk.InputAttributes["value"].ToString());
lblProba.Text +="in if clause; element count="+ myche.Count.ToString();
}
else
{
lblProba.Text += "enering else;element count:"+myche.Count.ToString();
}
lblProba.Text += "Final length" + myche.Count.ToString();
for (int t = 0; t < myche.Count; t++)
{
Session["chk"]+= myche[t];
}
}
In a web application you can think of every postback as leading to a completely new start of your application. It doesn't remember any state, all the objects are being instantiated as if it's the first time your application is running.
ASP.NET tries to hide this fact by employing things like ViewState etc., but nevertheless your server-side objects don't live beyond a single request/response cycle.
To carry state through multiple requests you could store intermediate values in the Session variable.
You need to check on the lifecycle of ASP.NET pages. Each time you call a page, ASP.NET creates a new instance of the page, loads it with any Viewstate data (if this is a postback) and passes control to your Load event. Once the page sends the response to the browser, the instance is destroyed.
ASP.NET manages ViewState for the statically created controls automatically. You will have to ensure that any data required to rebuild and populate your dynamic controls is saved in the ViewState and used to rebuild them in your Loaded event.
You should store your list e.g. in Session object to avoid losing it on every postback.
I'm trying to make a usercontrol work like a plugin: load it dynamically (using reflection) from a user's selection. After I click the button, I can see that the UI had adjusted to supposedly indicate that the user control has been loaded but I cannot the control itself. I even used viewstate but still I cannot see the control.
Please find my code below:
protected void Page_Load(object sender, EventArgs e)
{
//the scenario should be: a user clicking a button and from there,
//loads the control just below it, but still in the same page.
if (Page.IsPostBack)
LoadUserControl();
//(a)I also tried to put in a ViewState but still nothing happens.
//if (ViewState["UserControl"] != null)
//{
// UserControl uc = (UserControl)ViewState["UserControl"];
// pnlReportControl.Controls.Add(LoadControl());
//}
}
//supposedly done after a button click
private void LoadUserControl()
{
enrolmentReports = string.Concat(Server.MapPath("~"), enrolmentDll);
assembly = Assembly.LoadFrom(enrolmentReports);
Type type = assembly.GetType("TZEnrollmentReports.EnrollmentUserControl");
enrolmentMethodInfos = type.GetMethods();
//also tried this way but also didn't work
//Page.LoadControl(type, null);
UserControl uc1 = (UserControl)LoadControl(type, null);
pnlReportControl.Controls.Add(uc1);
//(a)
//ViewState["UserControl"] = uc1;
}
Please help. This is just the first step of the whole complicated process. I still have to get a dataset from that report. But I think I'm leaving that to another thread.
Thank you!
I believe that this is by design with the LoadControl(Type, Object) that it doesn't return what you are expecting.
If you change it to use LoadControl("PathOfControl") then this should work.
See this SO Q&A for more info Dynamically Loading a UserControl with LoadControl Method (Type, object[])
A suggestion that could help you solve this issue, is to change a little the approach. Usually developing a pluggable system, you base the pluggability to some interfaces. In your case, I would create an interface IPlugin that defines a method like CreateUI and some other to retrieve the data managed by the custom control internally, in some generic form.
This way, you'll delegate to the plugin implementation (your custom control) the responsability to create the UserControl properly and to return it to the caller (your page).
Once loaded the plugin implementation via reflection (something like this):
Assembly pluginDLL = Assembly.Load(System.IO.File.ReadAllBytes(fullPath));
Type pluginType = pluginDLL.GetType(step.PluginClass);
IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
then you can load the Control on your page:
pnlReportControl.Controls.Add(plugin.CreateUI());
try replacing following code in your page_load method
if (Page.IsPostBack) LoadUserControl(); with if (!Page.IsPostBack)
LoadUserControl();
For a data bound control it is common scenario where we provide data text field and data value field ( in simple controls like Dropdownlist) but more fields in controls like Gridview. Generally the datasource is of type IEnumerable.
How does the control internally process these values or rather how do they get the value from the data source without knowing what kind of datasource they are dealing with.
Can someone explain with code how the controls evaluate these fields from the data source.
Typically, the data-bound control (or concerned components such as
DataControlField in GridView) will handle DataBinding event.
Within event handler, the data item that is being currently bound (e.g. DataRowView or entity instance) is retrieved. This is done via DataBinder.GetDataItem passing the actual control or control's NamingContainer. For example, if you are implementing a lower level control such as DataControlField for higher level data-bound control such as GridView then it would handle data-binding of a cell control and hence it will use cell's naming container to pass to DataBinder.GetDataItem method which uses current data binding context to get the same.
Once the data item object is retrieved, one need to evaluate the given data-binding expression against it to get the actual value and apply any formatting as per different properties set to the control/component. The most simple way is to use DataBinder.Eval overload. However, one may use the more efficient ways - for example, say DataField string is going to be only property name then you may look and cache the property descriptor and then use the same against different data items.
I will suggest you to use tool such as Reflector to inspect relevant control's code to get the better idea.
I never knew i could find this information so easily and LLyod was in fact wrong on using reflection to find data from a datasource. None of the data controls use it when i inspected through Reflector ;(
link that solved the problem
http://msdn.microsoft.com/en-us/library/ms366540.aspx
how you do it is below
protected override void PerformDataBinding(IEnumerable retrievedData)
{
base.PerformDataBinding(retrievedData);
// Verify data exists.
if (retrievedData != null)
{
string dataStr = String.Empty;
foreach (object dataItem in retrievedData)
{
if (DataTextField.Length > 0)
{
dataStr = DataBinder.GetPropertyValue(dataItem,
DataTextField, null);
}
else
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(dataItem);
if (props.Count >= 1)
{
if (null != props[0].GetValue(dataItem))
{
dataStr = props[0].GetValue(dataItem).ToString();
}
}
}
}
}
}
If the above code seem Greek and Latin , you will have to have a course on asp.net controls development to understand what is being done.
I have a GridView bound to ObjectDataSource. I see, the SelectMethod and the SelectCountMethod are fired twice.
In the GridView RowDataBound I have gv.ShowFooter = false;
When I comment this line, the events are fires only once. Why is that happening? How to work around it? I don't understand, why hiding one element in the databound control results is rebinding the ObjectDataSource?
RowDataBound event gets fired when GridView gets data bound (that means firing of SelectMethod).
Now, toggling properties like ShowFooter requires grid to re-create rows and it means binding the data again. That's why object data source will get triggered again.
Solution will be to set ShowFooter property earlier (instead of RowDataBound). If that's not feasible then put the logic in your object data source class to the cache the data so that you don't have to visit data store twice. For example,
// Code Behind Class
public partial class MyPage : System.Web.UI.Page
{
private object _data;
public static object SelectData()
{
// get the current page instance
var page = HttpContext.Current.CurrentHandler as MyPage;
if (null != page._data)
{
return page._data;
}
// logic to retrieve the data
...
_data = ...
return _data;
}
...
private void RefreshGrid()
{
_data = null; // force the data-source to go to database again
grid.DataBind();
}
}
Disclaimer: un-tested code only for illustration purpose
So, in above code, a static method for page code-behind is used to getting the data. And a local variable in the page class is used for caching the data. Also note for refreshing the grid, you may need to clear the variable before calling DataBind method on grid.
I'd like to localize my aspx-page.
This should include dynamically created LinkButtons in a GridView inside of InstantiateIN
(amendment 1: implementation of the System.Web.UI.ITemplate.InstantiateIN method to manipulate the appearance of a GridView)
(amendment 2: first six lines of code added to better indicate location of other code)
But inside InstantiateIN I cannot use (see) the method GetLocalResourceObject
Solution: use a Session-Variable
Question: Why can't I use GetLocalResourceObject inside InstantiateIN?
the following happens inside InstantiateIN
public class DynamicTemplateGridViewSearch : ITemplate
{
public void InstantiateIn(System.Web.UI.Control Container)
{
switch (ItemType)
{
case ListItemType.Item:
switch (InfoType)
{
case "Command":
{
LinkButton search_button = new LinkButton();
search_button.ID = "search";
search_button.CommandName = "Edit";
//following line does not work. Error is:
//The name 'GetLocalResourceObject' does not exist in the current context
search_button.Text = GetLocalResourceObject("SearchButtonResource1.Text").ToString();
//so I have to create a Session-String in Page_Load
//which is referenced here
search_button.Text = (string)new Page().Session["SearchText"]; // "Search";
search_button.Click += new EventHandler(search_button_Click);
Container.Controls.Add(search_button);
You haven't told where exactly InstantiateIn method is located - is it inside an custom control?
Regardless, you can use container.Page property to get reference to page object and invoke the method on it. For example,
search_button.Text = Container.Page.GetLocalResourceObject("SearchButtonResource1.Text").ToString();
BTW, session object reference can be obtained similarly or you may use current HttpContext. For example, Container.Page.Session["SearchText"] OR HttpContext.Current.Session["SearchText"]