Saturday, March 24, 2012

Modal Popup, Grid View, and Data Binding...

I'll tell you what I am trying to do, and how I have attempted to accomplish it so that someone can tell me if I am totally in the wrong direction, or how to get working what I am trying to do.

I have a gridview with an select command button. I would like to popup a modal extender for each row when the select button is clicked so the user can view/edit the data in a form view in teh popup. My assumption is that I would need a ModalPopupExtender for each row in the gridview to accomplish this. I am trying to avoid using ItemTemplate and accomplish this through using Bound Fields.

So I headed into the code behind to try to spin up my MPE's on the fly with each row as it was databound. Here is my code...

<asp:GridView ID="GridView1" CssClass="grid" runat="server" GridLines="None" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" DataSourceID="society" OnRowDataBound="GridView1_RowDataBound"> <Columns> <asp:CommandField ShowSelectButton="True" /> <asp:CommandField ShowDeleteButton="True" /> <asp:BoundField DataField="FirstName" HeaderText="First Name" SortExpression="FirstName" /> <asp:BoundField DataField="MiddleName" HeaderText="Middle Name" SortExpression="MiddleName" /> <asp:BoundField DataField="LastName" HeaderText="Last Name" SortExpression="LastName" /> <asp:BoundField DataField="Gender" HeaderText="Gender" SortExpression="Gender" /> <asp:BoundField DataField="BirthDate" HeaderText="Birth Date" SortExpression="BirthDate" /> <asp:BoundField DataField="Address1" HeaderText="Address 1" SortExpression="Address1" /> <asp:BoundField DataField="Address2" HeaderText="Address 2" SortExpression="Address2" /> <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" /> <asp:BoundField DataField="State" HeaderText="State" SortExpression="State" /> <asp:BoundField DataField="Zip" HeaderText="Zip" SortExpression="Zip" /> </Columns> <RowStyle CssClass="gridRow" /> <AlternatingRowStyle CssClass="gridAltRow" /> <SelectedRowStyle CssClass="gridSel" /> <HeaderStyle CssClass="gridHeader" /></asp:GridView>

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) {if (e.Row.RowType == DataControlRowType.DataRow) { TableCell tc = e.Row.Cells[0]; Control anchor = tc.Controls[0]; anchor.ID ="a" + e.Row.RowIndex; AtlasControlToolkit.ModalPopupProperties mpp =new AtlasControlToolkit.ModalPopupProperties(); mpp.TargetControlID = anchor.UniqueID; mpp.PopupControlID ="popup"; mpp.DropShadow =true; mpp.OkControlID ="OkButton"; mpp.CancelControlID ="CancelButton"; AtlasControlToolkit.ModalPopupExtender mpe =new AtlasControlToolkit.ModalPopupExtender(); mpe.TargetProperties.Clear(); mpe.TargetProperties.Add(mpp);// no error on this line of code, but I get an 'Object reference not set to an instance of an object' later tc.Controls.Add(mpe); } }

This code executes, but somewhere later down the line I get an 'Object reference not set to an instance of an object'. I have looked at the mpe object I am adding to the table cell's control collection and I see the same stuff with TargetControlID that others have mentioned. The property is not actually there. There is a TargetControl object though and it is null. I am assuming this is my issue. I am not sure what the control does internally to "get" the control once you set TargetControlID. Is there something else I need to do in the code above to get this to "link" up? Is this even my problem?

Thanks,

Stoney

Well, as I got further with this I realized you are correct. I only need one per page. I also needed to let the grid post back to allow my data source for my form view to be filtered before displaying it ion the popup. So for now I used the info in another post to programattically open the Modal Popup after a post back for the Selected Index Changed event on the gridview where I do my filtering.

Thanks for the input.


I'm thinking you only want one ModalPopupExtender per page and then just populate it with ModalPopupProperties objects as necessary. If that doesn't help get you going further, Shawn's looking into an issue like this one and may have additional suggestions.
Can you point me to the post that show how to programmattically open the Modal Popup?
http://forums.asp.net/thread/1277867.aspx

Could you post the code you have which opens a modal popup from a button in a gridview. I just cant get it to work.

Thanks

N


Ok, here is what I ended up doing.

1. put a grid view in an update panel with an id of "GridView1" Mine is bound to an objectdatasource called society.

 <asp:Panel ID="collapse" runat="server" CssClass="collapsePanel"> <atlas:UpdatePanel runat="server" ID="up"> <ContentTemplate> <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" DataSourceID="society"> <Columns> <asp:CommandField ShowSelectButton="True" /> <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" /> <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" /> <asp:BoundField DataField="MiddleName" HeaderText="MiddleName" SortExpression="MiddleName" /> <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" /> <asp:BoundField DataField="Gender" HeaderText="Gender" SortExpression="Gender" /> <asp:BoundField DataField="BirthDate" HeaderText="BirthDate" SortExpression="BirthDate" /> <asp:BoundField DataField="Address1" HeaderText="Address1" SortExpression="Address1" /> <asp:BoundField DataField="Address2" HeaderText="Address2" SortExpression="Address2" /> <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" /> <asp:BoundField DataField="State" HeaderText="State" SortExpression="State" /> <asp:BoundField DataField="Zip" HeaderText="Zip" SortExpression="Zip" /> </Columns> </asp:GridView> </ContentTemplate> </atlas:UpdatePanel>

2. Add a second update panel set to Mode="Always" and put an asp:Textbox in it with the ID "popupID", style="display:none" and EnableViewState="False" This textbox' value will be set in the code behind with the id of the mpe you wish to open. If you don;t set this panel to Mode="Always", the textbox won't write out its new value when you change it in the code behind.

 <atlas:UpdatePanel runat="server" ID="up2" Mode="Always" RenderMode="Inline"> <ContentTemplate> <asp:TextBox runat="server" ID="popupID" Style="display: none;" EnableViewState="false"></asp:TextBox> </ContentTemplate> </atlas:UpdatePanel>

3. Add your modalpopupextender to the page. Make sure to add an ID attribute to the ModalPopupProperties with the ID of "mpepop" Also add a hidden button to your page to dummy up something for the mpe to point at. You'll still want your command button in the grid to postback so you can do any work necessary to filter the data if needed for your popup. If you point the mpe at your command button, you'll lose your postback.

 <atlasToolkit:ModalPopupExtender ID="mpe" runat="server"> <atlasToolkit:ModalPopupProperties TargetControlID="hiddenbutton" PopupControlID="form" BackgroundCssClass="modalBackground" DropShadow="false" OkControlID="OkButton" CancelControlID="CancelButton" ID="mpepop" /> </atlasToolkit:ModalPopupExtender> <div style="display: none"> <asp:LinkButton ID="hiddenbutton" runat="server"></asp:LinkButton> </div>

4. Add a hidden div with the ID "bindingstatus"

 <div id="bindingstatus" style="display: none;"> </div>

5. Add your popup content div with the id of "form"

 <div style="display: none"> <asp:Panel ID="form" runat="server" CssClass="modalPopup"> <asp:Button ID="OkButton" runat="server" Text="OK"></asp:Button> <asp:Button ID="CancelButton" runat="server" Text="Cancel"></asp:Button> </asp:Panel> </div>

6. Now for the stuff that makes it all work. You need to add your own binding to the xml-script at the bottom of your page. Add the following to the components section of the xml. This points at the hidden div you created. It will cause the javascript function indicated in the transform property to fire after the page has finished loading and the atlas stuff has been initialized. In the transformerArgument I put the client ID of our hidden textbox. It is hardcoded for now, which needs to be fixed. Eventually I'll be adding this binding from code so I will have access to not hardcode it then.

 <control id="bindingstatus"> <bindings> <binding dataContext="_PageRequestManager" dataPath="inPostBack" property="associatedElement" propertyKey="innerHTML" transform="deferredPopup" transformerArgument="popupID" direction="In" /> </bindings> </control>

7. Add a javascript funtion called deferredPopup that the binding will call. I added this script block to the page after the xml-script. This gets the textbox whose value should be the ID of the popup to open. Then it calls the _show method on that popup.

 function deferredPopup(sender, e) { var component = document.getElementById(e.get_transformerArgument()); if(component.value != '') { var popup = $object(component.value); if(popup) { component.value = ''; popup._show(); } else { debug.trace('component not found...'); } } }

8. Add the code to the selectedIndexChanged event of your GridView to set the ID of the popup you wish to open in your hidden textbox.

protected void GridView1_SelectedIndexChanged(object sender, EventArgs e) { popupID.Text ="mpepop"; }

I know that this still needs some polish, but it works. If anyone has any ideas on how to make this better, or if I have gone completely the wrong direction, let me know.

Thanks,

Stoney


P.S.

The pas:panel wrapping the updatepanel and grid is missing it's closing tag

The javascript is missing a closing }

The gridview above is missing the event attribute for the selectedindexchanged...

OnSelectedIndexChanged

="GridView1_SelectedIndexChanged"

Thanks Stoneym, I will try this out tomorrow.

N


I followed this to the "T" and I am getting the following error message and dont know why. Any help is greatly appreciated!!

Error Message:

Assertion Failed: Could not resolve reference to object named "_PageRequestManager" for "dataContext" property on object of type "Sys.Binding"

Next error message:

Assertion Failed: No data context available for binding with ID "" and dataPath "inPostBack" on object of type "Sys.UI.Control"


TPeterson:

I followed this to the "T" and I am getting the following error message and dont know why. Any help is greatly appreciated!!

Error Message:

Assertion Failed: Could not resolve reference to object named "_PageRequestManager" for "dataContext" property on object of type "Sys.Binding"

Next error message:

Assertion Failed: No data context available for binding with ID "" and dataPath "inPostBack" on object of type "Sys.UI.Control"

sorry about that. This is a bug with atlas. Make sure your script manager has the EnablePartialRendering set to true.


Thanks, that worked!

I like your idea on another thread about taking this modal popup from the grid and showing the details of that row. I am looking to do the same thing.


Well, you're in the home stretch now. This post was all about getting the modal popup to trigger without eating the postback from the grid so the selectedindexchanged would still fire. Now that you have this working, it should be trivial to load up a form view in the modal popup with the selected record. We have it all working here and it flows pretty nice.

I assume the thread you mention is this one?http://forums.asp.net/thread/1289843.aspx

IDisposable and I are still working further on this with combining the modalpopup and popup to one control because we like some of the behavior of the popup for our modalpopup. In the meantime, the final javascript that IDisposable posted is, in my opinion, a great improvement to the original. Read the thread for details. You may want to look at pulling that in.


Yes, I was referring to that post. The detail data that I want to show is more complex than just a formview. It would consist of 3 different gridviews and some textboxes. Can this be accomplished this way? If so, I dont understand how to hook up the selectedindex from the main grid to get its key value to populate the data on the popup?

Thanks!


TPeterson:

Yes, I was referring to that post. The detail data that I want to show is more complex than just a formview. It would consist of 3 different gridviews and some textboxes. Can this be accomplished this way? If so, I dont understand how to hook up the selectedindex from the main grid to get its key value to populate the data on the popup?

Thanks!

In my case I used a seond sqldatasource on the page for the formview. I set it up with a parameter of the selectedindex of the grid. When the main grid's select command button is clicked, the second datasource automatically filters on postback so that when the formview on the popup is rendered, it gets the filtered data. The very same thing could be done with the controls on your popup. If your textboxes are not databound, you can populate those in the selectedindexchanged event on your main grid.

No comments:

Post a Comment