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();
Related
Let's say that in an ASP.NET .aspx page I have the Page Load method and another method for a button click event.
In the Page Load method I'm checking if the user is logged in by checking the Session. Whether he is or not, I'm storing the result in a Global Variable.
Boolean isGuest = false;
protected void Page_Load(object sender, EventArgs e) {
if(Session["id"]==null)
isGuest = true;
else
isGuest = false;
}
Let's say 20 minutes have passed, and I don't know if the Session has terminated or not, and then I click a Button, the event goes like this:
protected void Button_Click(object sender, EventArgs e) {
if(isGuest==false)
//do something
else
// do another thing
}
My Question is : When I'm clicking the button, does ASP.NET go through the Page_Load method again (check isGuest again) or it simply executes what's inside the Button_Click method, means, it uses a Boolean isGuest that could be false, but in reality the session is terminated, means it should be true.
Page_Load is triggered always before the control events.
Have a look: ASP.NET Page Life Cycle Overview
Side-note: If you want to do things only on the first load and not on every postback you have to check the IsPostBack property.
You can:
Define your own class with the UserID, and other profile properties;
Add that class to session in the global.asax session started event Session["NameReferingToYourClass"] = new YourClass();
Set a member variable to your session object early in the page life cycle mYourClass = Session["NameReferingToYourClass"] casted if you need to;
Then you can make any changes to your class anywhere in the code your member variable is available;
Save back your class with all the changes into session on the Page.Unload(..){ Session["NameReferingToYourClass"] = mYourClass.
This way you are using your class properties in your code, including UserId, pretty much like a windows application, there will be no mentioning of session anywhere else in your code.
I have asp.net page which loads the user controls at run time I want to capture the save/cancel event of page on the user control.
User control will be load at run time so, for further development I don't want to change my code on page level.
Any help.
I solve it, with the help of observer pattern but with some more modification because my challenge is Page don't know which user control will be load on run-time in its place holder.
I create change-manager which holds the Observers references with their intended types(submit,cancel,viewonly)
Page holds the reference of change-manager and call the notify of change manager with (eventtype(enum),response(this.response object)) then change manager calls the update method In this method call Observers, kept in the dictionary of change-manager.
Iterate the dictionary and call their updates according to their interested event types.
Now I am free to remember the user-control reference of any type of casting.
see below example of get user control from page you need to use public modifier
///user control code see event is public
public void btn1_Click(object sender, EventArgs e)
{
///do you stuff
}
/// page code
protected void Page_Load(object sender, EventArgs e)
{
uc1.btn1_Click(sender,e);
}
In my application, I have a form that users fill out, then gets approved by a manager. I have various types of forms that all use the same process, so the approval buttons are all done via a user control (which includes the functionality to update the data in the database and call the postback).
However, once I click on the "Approve" button (which is in the user control), the form information doesn't update (it still says "unapproved"). A postback is definitely happening, but not sure why the page isn't updating properly.
I can confirm that the change are being made - when I manually reload the page, it gets updated - but not on the post back.
What am I missing here?
My page:
protected void Page_Load(object sender, EventArgs e)
{
int ID;
// ensure that there's an ID set in the query string
if (Int32.TryParse(Request.QueryString["ID"], out ID))
PopulatePage(ID);
else
Response.Redirect("~/Default.aspx");
}
}
protected void PopulatePage(int ID)
{
using (WOLinqClassesDataContext db = new WOLinqClassesDataContext())
{
lblStatus.Text = wo.Workorder.status;
....
}
}
I think that the Page_Load happens before the code in the submit button. To check this just use a couple of breakpoints. So the page loads the old data since the new data are not saved yet.
You should call a method to load the data inside the OnClick method of the Approve button.
After you've submitted the changes to the database, try running db.Refresh(RefreshMode.OverwriteCurrentValues) to force the changes to be reloaded into the data context.
I'm recently mining a website to build some database. I already built a python script parsing retrieved information but the problem is that it requrires a query word to retrieve web pages which contain information I want to see. And this page is in POST method so I cannot see how this page retrieves a page list.
To describe an outline for your clear understanding:
1. on inputKeyword.aspx : This contains a form to input a query(let's say ID)
When I input an ID and press search, it retrievs a
relevant list
2. Press Search
3. on inputKeyword.aspx : A relevant list is showed on the same aspx page
(which means POST method), so I cannot see how this query
works on inputKeyword.aspx page.
It would be so much easier if this webpage is in GET method, since I can simply hook a url with queries, but it's not possible in POST method.
Is there any way that I can open step #3 skipping step #1 and #2?
The webpage is built in asp.net but there's no restriction on languages as long as there's way to do this.
If I understand correctly you want to be able to accept a an ID as part of your query string. eg
http://your.domain.com/inputKeyword.aspx?ID=555
So in the pages load event you can check the request object for query params, ie Request.QueryString[param] as the following example shows
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["ID"];
if (!string.IsEmptyOrNull(id))
{
//do something with the requested identifier
}
}
Note: you can use Page.IsPostBack() to determine if the page is being hit for the first time or is posting back as a result of a button click.
To get your Search button to behave correctly you have a couple of options. For example; you can use javascript to capture the buttons onclick event and redirect the page to itself with the url amended to include the identifier from the id textbox.
But perhaps the following is the easiest, keeping the code all server-side:
private _identifer string;
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["ID"];
if (!string.IsEmptyOrNull(id))
{
_identifer = id;
}
}
protected void SearchButton_Click(object sender, EventArgs e)
{
_identifer = IdentiferTextbox.Text;
}
protected void Page_PreRender(object sender, EventArgs e)
{
if (!string.IsEmptyOrNull(_identifer))
{
PopulateListForidentifer(_identifer);
}
}
Basically the example shows that you can cope with scenarios. ASP.Net's page life cycle means that events are processed in the following order Page_Load -> Control Events (eg button click) -> Page PreRender.
If the page is hit for the first time without an identifier in the url, PopulateListForidentifer method isn't called since _identifer is never set.
But if the url contains an identifier then _identifer is set in the page load event, when the page pre-render is called PopulateListForidentifer will be called.
Finally if the page is posting back to itself because the search button has been hit then the click handler is called and _identifer is set to the content of the IdentiferTextbox; the pages prerender is called and also PopulateListForidentifer. Note this would override the point about ie when the identifer was passing as part of the url.
From what I understand, it seems you want to simulate the HTTP Post operation in your Search form, where by without entering the ID and clicking search, you directely want to have access to the search results.
Here is a Blog Post by Scott Hanselman, where he discusses a similar topic using WebClient.
You may also want to check this thread
I am working on a Silverlight application using V3 SP1 of MVVM Light Toolkit.
My application is fully French/English. All UI elements (buttons, labels, etc.) and all the data (models). I need dynamic language switching and this is fully implemented and works with anything coming from a resource file. What I am struggling with is the ViewModels.
The Models have language specific prperties (DescriptionEn, DescriptionFr) and an additional property call LocalizedDescription which uses the current culture to return call the language specific property.
When the language changes (via a button click) I raise and broadcast (via the Messenger) a property changed event.
In each of my ViewModels, I register to receive the property changed message for the language swap.
I want to notify all the properties of the ViewModel that something has changed.
From: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx
The PropertyChanged event can indicate all properties on the object have changed by using either null or String.Empty as the property name in the PropertyChangedEventArgs.
However, since the toolkit abstracts the raising of the changed event with RaisePropertyChanged(...) I cannot get this to work. I have also examined the source of the tookit and discovered that RaisePropertyChanged calls VerifyPropertyName(..) which in turn returns an error is the property does not belong to the ViewModel. I also noticed that the VerifyPropertyName method is attributed with Conditional("DEBUG"), but even if I choose the Release configuration, the ArgumentException("Property not found") is still raised.
Does anyone know of a way to get this to work using the toolkit aside from manually calling RaisePropertyChanged for every property of the ViewModel?
Follow-up:
Based on the comment from Simon, I attempted to create my own class that extends ViewModelBase. I looked at the source on CodePlex and decided to create a single method called RaiseAllPropertyChanged(). It would simply be a copy of the RaisePropertyChanged(string propertyName) but without the parameter and without the call to VerifyPropertyName(...). I cannot get it to work. Here is what I have.
public class ViewModelBaseExtended : ViewModelBase
{
protected void RaiseAllPropertyChanged()
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(String.Empty));
}
}
}
But I get a compiler error: The event 'GalaSoft.MvvmLight.ViewModelBase.PropertyChanged' can only appear on the left hand side of += or -=. This is a copy of the code that is used in the ViewModelBase.
Can someone offer some advice as to how to get this to work?
Solution:
I copied all the code from ViewModelBase into a new class. I then added the method RaisePropertyChanged() mentioned above which instantiates the PropertyChangedEventArgs class with String.Empty. This is now the new subclass for my ViewModels.
Thanks again to Simon for leading the way!
In case you're reading this in 2016, you can use ObservableObject and notify that all of the properties have changed by doing:
RaisePropertyChanged(string.Empty);
Unfortunately this is not possible with the current code-base of MVVMLight
In the short term your have 2 options:
User your own custom base class. And by custom base class I mean "Do not inherit from the MVVMLight class".
Download and compile MVVMLight in Release mode. This will force the "VerifyPropertyName" method to be excluded. Of course then you don't get the value of property name checks.
I am sure Laurent Bugnion will have this fixed soon.
A lighter solution to this problem would have been to override RaisePropertyChanged(string propertyName) in your class :
protected override void RaisePropertyChanged(string propertyName)
{
if (propertyName != null)
{
base.RaisePropertyChanged(propertyName);
}
else
{
var handler = PropertyChangedHandler;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(null));
}
}
}