ASP.NET MVP - Utilizing User Controls - asp.net

I'm writing my first app with ASP.NET MVP (attempting Supervisory Controller) and Unit Testing (better late than never!), and I've run into a bit of a dilemma. I've written 3 User Controls, all tested and Interfaced up, Presenters in tow. Now I have come to a Page which takes these three User Controls and encountered the following problem:
User Control 1 is DateSelector, it's a Calendar control with a couple of other buttons/lists. Nothing real exciting.
User Control 2 is DailyList. Guess what it is. Anyway, you can select/delete etc.. if you select an item from the gridview, it needs to populate User Control 3.
User Control 3 is ItemDetail. Here are the DropDownLists, TextBoxes, etc... some with existing dependencies on others (selecting an option in DropDown one affects the options in DropDown 2).
If I select a new Date from my DateSelector, do I raise the event from the DateSelector Presenter? I have to somehow let the other User Controls know that a new date was selected, so that they can rebind their data, but how? If I use the Page's Presenter to subscribe to the Presenters of the User Control Views, will I not be blatantly breaking the Law of Demeter (exposing the Presenters as Properties through their Views)? Mustn't I use the Page's Presenter as the All-Knowing Controller of the page? Is there something I am missing?
Everything I've read so far says, "MVP is great, even with User Controls", but the use of User Controls is conveniently forgotten about when it comes to examples. It appears to me MVC would more closely match my pattern of thinking on this one, but currently, MVC is not an option. Any help would be great here. Thanks in advance.

The Page Presenter has to be the one to coordinate the interactions between the controls on the page. Who else would do it? I'd have the page presenter listen in on the event of the DateSelector user control. From the page presenter's perspective, it probably doesn't need to know who raised the event (view or presenter) as it looks at the DateSelector as a fully encapsulated control. The internal workings should be hidden from the page's presenter.
All it knows is that the DateSelector user control raised an event, and now it needs to notify the other controls on the page, either by raising its own event, or by explicitly calling methods on the presenter.

Related

ASP.NET Web Forms - Model View Presenter and user controls

I'm new to using the MVP pattern and I just want to make sure on the best way to call a presenter from within a user control.
MyPage.aspx has a presenter MyPresenter
The page contains a user control which accepts MyPage's Presenter via a property which I setup from MyPage
MyUserControl.Presenter = this.Presenter
I'm now trying to call Method1 within the presenter which retrieves some config and sets it on the view from the user control.
Presenter.Method1(); // calls method and sets config to the view
My question is firstly
should I be using the presenter in the user control in this way?
If so, is it valid to be accessing the view value via the user control as shown below.
Presenter.View.MyData
I just want to make sure I'm not going off down the completely wrong path with this!
What I use to do is to have one presenter for each user control which is responsible only for the user control presentation and one presenter for each page (.aspx).
I think keeping things separated helps also for maintaining as you will have "skinny" presenter which are responsible only of a small section of the UI.
The user control will be also "self-contained" in the way that you can reuse them as the presentation logic is kept separated from the page presentation logic.
have a look at the following post:
MVP and UserControls and invocation

Dynamically creating many instances of ASP.NET usercontrols: How do I create it, and where will my conflicts be?

I haven't seen this implemented before in ASP.NET, but am thinking about a UI that would look and act like this:
Conceptual Overview
A TabControl is loaded and the first tab contains a grid
When a row is double-clicked, a new tab is created with the record detail
The content of the tab/record detail is created by a usercontrol
Many tabs could be created, and therefore many instances of the usercontrol will be created
I know ASP.NET will rename my (runat="server") ID's for me, and that I can use jQuery or ASP.NET server-side code to work with the ID's... My concerns are:
How can I ask ASP.NET to generate a unique ID for each Nth instance of my usercontrol (to be rendered in a placeholder)
How do I actually create that extra instance of the control?
What else do I need to keep in mind?
Since I don't want postbacks I'm considering basing my implementation off of ComponentArt's Callback Control, and using ASP.net usercontrols to achieve this effect. This will allow me to do most things that require a postback, but won't refresh all the elements on a page... just the section that contains the user control. That being said, I'm not tied to a particular implementation.
You should look into the Page.LoadControl method. It works nicely and as far as I remember you put placeholders on your page and load the controls into the PlaceHolders, that's how you control the ids.
One thing that doesn't work out so well with this approach is when your control raises events that your Page object has to handle. If your control is selfcontained however you shouldn't have a problem.
This might help you get started:
http://www.codeproject.com/KB/aspnet/LoadingUSerControl.aspx

ASP.Net MVC - What replaces events to support loose coupling?

What feature(s) of ASP.Net MVC can replace the way events can be used in Webforms to support loosely coupled components?
For example, take a simple pager control in Webforms:
A page number is clicked
Pager fires off a "PageChange" event with the new page number
This subscribing page/control received the event and handles initiating a call to fetch and bind new data.
What tools are available in ASP.Net MVC to similarly support
Loose coupling
Component re-usability
Separation of logic for a single page/view (such a very complex "portal" type page).
ASP.NET MVC, and the Model-View-Controller in general, support loose coupling and separation of concerns by keeping the data and code that supports an application separate from the visual "Presentation-layer" markup that is seen by users.
Designed properly, Controllers and Views in MVC can be reused so that the Edit View for an entity can be "embedded" into a related View with no modification.
For example: an Orders View might include an OrdersDetail partial view. That partial view could be replaced with the OrderDetail Edit View that is also available elsewhere within the application.
Separating the Model from the View makes unit testing more effective and less cumbersome by splitting the code from the context of the presentation layer. You don't want to have to reference System.Web to unit test code that fetches data from a database.
MVC does away with events because events for the most part are just an unnecessary layer between what the client is trying to tell the server to do and the server actually doing it.
In the paging example for webforms the client clicks the button, the browser sends the event/viewstate, and the engine fires the ButtonClicked event. You examine the event, determine the client is intending to page, and you execute the paging logic.
In the MVC paradigm the user clicks a button that makes a request directly to the code that executes the paging logic. Since you know what action the button is supposed to invoke when you put it there why go through all machinations of the event firing? In your controller you certainly could fire an event when you get the command but I honestly can't imagine the use case for doing so.
Both methods accomplish the same thing but MVC just removes a layer of complexity.

How to call a method of an user control from a page in asp.net 2.0?

I have a usercontrol used in a masterpage.
I have added a page with the masterpage.
Now I need to call a method of the user control from the page.
How to do this? Please help.
Assuming that your method is public and your user control's type is YourUserControlsType, try this :
YourUserControlsType ctrlAtMasterPage =
(YourUserControlsType)Page.Master.FindControl("YouControlsID");
ctrlAtMasterPage.YourPublicMethod();
This should get you your control even if it was added programatically:
In a member of the page you added:
TextBox FoundTextBox = (TextBox)this.Master.FindControl("RunAtServerTextBoxServerID");
If you don't have a member reference to the control you should consider decoupling the page from the control. In an ideal world, the page should not necessarily know about a control it may or may not contain. Therefore, you might look into an implementation of the MVP pattern.
There's a simple implementation of MVP here, and you can see the decoupling in action here. If you reverse the communication from the decoupling example (i.e. page fires an event that the control picks up), then basically, you've decoupled your page from the control. This has a benefit in that if your page changes and the control is no longer in use, the event is not picked up by anything and your page continues to execute with no problems. I find this much more suitable than a potential null reference exception when FindControl doesn't find the control and then you try to execute a method on it.
While decoupling may take a few extra minutes, in many scenarios it turns out to be a worthwhile endeavor.

Dynamically added controls in Asp.Net

I'm trying to wrap my head around asp.net. I have a background as a long time php developer, but I'm now facing the task of learning asp.net and I'm having some trouble with it. It might very well be because I'm trying to force the framework into something it is not intended for - so I'd like to learn how to do it "the right way". :-)
My problem is how to add controls to a page programmatically at runtime. As far as I can figure out you need to create the controls at page_init as they otherwise disappears at the next PostBack. But many times I'm facing the problem that I don't know which controls to add in page_init as it is dependent on values from at previous PostBack.
A simple scenario could be a form with a dropdown control added in the designer. The dropdown is set to AutoPostBack. When the PostBack occur I need to render one or more controls denepending on the selected value from the dropdown control and preferably have those controls act as if they had been added by the design (as in "when posted back, behave "properly").
Am I going down the wrong path here?
I agree with the other points made here "If you can get out of creating controls dynamically, then do so..." (by #Jesper Blad Jenson aka) but here is a trick I worked out with dynamically created controls in the past.
The problem becomes chicken and the egg. You need your ViewState to create the control tree and you need your control tree created to get at your ViewState. Well, that's almost correct. There is a way to get at your ViewState values just before the rest of the tree is populated. That is by overriding LoadViewState(...) and SaveViewState(...).
In SaveViewState store the control you wish to create:
protected override object SaveViewState()
{
object[] myState = new object[2];
myState[0] = base.SaveViewState();
myState[1] = controlPickerDropDown.SelectedValue;
return myState
}
When the framework calls your "LoadViewState" override you'll get back the exact object you returned from "SaveViewState":
protected override void LoadViewState(object savedState)
{
object[] myState = (object[])savedState;
// Here is the trick, use the value you saved here to create your control tree.
CreateControlBasedOnDropDownValue(myState[1]);
// Call the base method to ensure everything works correctly.
base.LoadViewState(myState[0]);
}
I've used this successfully to create ASP.Net pages where a DataSet was serialised to the ViewState to store changes to an entire grid of data allowing the user to make multiple edits with PostBacks and finally commit all their changes in a single "Save" operation.
You must add your control inside OnInit event and viewstate will be preserved. Don't use if(ispostback), because controls must be added every time, event in postback!
(De)Serialization of viewstate happens after OnInit and before OnLoad, so your viewstate persistence provider will see dynamically added controls if they are added in OnInit.
But in scenario you're describing, probably multiview or simple hide/show (visible property) will be better solution.
It's because in OnInit event, when you must read dropdown and add new controls, viewstate isn't read (deserialized) yet and you don't know what did user choose! (you can do request.form(), but that feels kinda wrong)
After having wrestled with this problem for at while I have come up with these groundrules which seems to work, but YMMV.
Use declarative controls whenever possible
Use databinding where possible
Understand how ViewState works
The Visibilty property can go a long way
If you must use add controls in an event handler use Aydsman's tip and recreate the controls in an overridden LoadViewState.
TRULY Understanding ViewState is a must-read.
Understanding Dynamic Controls By Example shows some techniques on how to use databinding instead of dynamic controls.
TRULY Understanding Dynamic Controls also clarifies techniques which can be used to avoid dynamic controls.
Hope this helps others with same problems.
If you truly need to use dynamic controls, the following should work:
In OnInit, recreate the exact same control hierarchy that was on the page when the previous request was fulfilled. (If this isn't the initial request, of course)
After OnInit, the framework will load the viewstate from the previous request and all your controls should be in a stable state now.
In OnLoad, remove the controls that are not required and add the necessary ones. You will also have to somehow save the current control tree at this point, to be used in the first step during the following request. You could use a session variable that dictates how the dynamic control tree was created. I even stored the whole Controls collection in the session once (put aside your pitchforks, it was just for a demo).
Re-adding the "stale" controls that you will not need and will be removed at OnLoad anyway seems a bit quirky, but Asp.Net was not really designed with dynamic control creation in mind. If the exact same control hierarchy is not preserved during viewstate loading, all kinds of hard-to find bugs begin lurking in the page, because states of older controls are loaded into newly added ones.
Read up on Asp.Net page life cycle and especially on how the viewstate works and it will become clear.
Edit: This is a very good article about how viewstate behaves and what you should consider while dealing with dynamic controls: <Link>
Well. If you can get out of creating controls dynamicly, then do so - otherwise, what i whould do is to use Page_Load instead of Page_Init, but instead of placing stuff inside the If Not IsPostBack, then set i just directly in the method.
Ah, that's the problem with the leaky abstraction of ASP.NET web forms.
Maybe you'll be interested to look at ASP.NET MVC, which was used for the creation of this stackoverflow.com web site? That should be an easier fit for you, coming from a PHP (thus, pedal-to-the-metal when it comes to HTML and Javascript) background.
I think the answer here is in the MultiView control, so that for example the dropdown switches between different views in the multi-view.
You can probably even data-bind the current view property of the multiview to the value of the dropdown!
The only correct answer was given by Aydsman. LoadViewState is the only place to add dynamic controls where their viewstate values will be restored when recreated and you can access the viewstate in order to determine which controls to add.
I ran across this in the book "Pro ASP.NET 3.5 in C# 2008" under the section Dynamic Control Creation:
If you need to re-create a control multiple times, you should perform the control creation in the Page.Load event handler. This has the additional benefit of allowing you to use view state with your dynamic control. Even though view state is normally restored before the Page.Load event, if you create a control in the handler for the Page.Load event, ASP.NET will apply any view state information that it has after the Page.Load event handler ends. This process is automatic.
I have not tested this, but you might look into it.

Resources