|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Adapting ReorderList WebControl for rendering dynamic htmlI need to be able to edit and render dynamic html from a custom data source. The rendered output is going to be html form elements for collecting survey style data. The main problem I´m facing is that the data which requires binding has a different structure for each item in the list, i.e. I need to loop through a list of objects which contain varied data and then render different html accordingly. For example, the first item in the list may require a label and textbox to be rendered, the second may require a label and populated CheckboxList. The ReorderList would be ideal I think if I can work out how to render different html depending on the data of each item in the list. I need the form creator to be able to sort the order of items. I also need to be able to render the html items as a static form so need to know if the ReorderList supports this. Can I create custom templates to use with the ReorderList, i.e. one for each type of data item (row)? Is this the best approach or should I consider a more custom approach e.g. overriding the BaseDataBoundControl in some way? I guess this is more work but may be necessary? I hope this makes sense but please let me know if you need more information. Many thanks Andrew Hi Andrew,
My name is Allen Chen. It's my pleasure to work with you on this issue. If my understanding is correct, you want to show different controls in each item of ReorderList control. To do this the general way is to put all the controls in the ItemTemplate and set their visibility according to our custom logic. Here's the sample that demonstrates how to do this: Aspx: <asp:ScriptManager ID="ScriptManager1" runat="server" /> <cc1:ReorderList ID="ReorderList1" runat="server" DataSourceID="ObjectDataSource1" AllowReorder="false" > <ItemTemplate> <asp:TextBox ID="TextBox1" runat="server" Visible='<%# SetTextBoxVisibility(Container) %>' Text='<%#Eval("Data") %>'></asp:TextBox> <asp:Label ID="Label1" runat="server" Visible='<%# SetLabelVisibility(Container)%>' Text='<%#Eval("Data") %>'></asp:Label> </ItemTemplate> </cc1:ReorderList> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="Select" TypeName="WebApplication2.BLL"></asp:ObjectDataSource> Aspx.cs: namespace WebApplication2 { public partial class WebForm1 : System.Web.UI.Page { public bool SetTextBoxVisibility(object container) { ReorderListItem item = container as ReorderListItem; if (item != null) { if (Convert.ToInt32(((MyData)item.DataItem).Data) % 3 == 0) { return true; } } return false; } public bool SetLabelVisibility(object container) { ReorderListItem item = container as ReorderListItem; if (item != null) { if (item.ItemIndex%2==0) { return true; } } return false; } } public class BLL { public IEnumerable Select() { //Test List<MyData> list = new List<MyData>(); for (int i = 0; i < 10; i++) { list.Add(new MyData() { Data = i.ToString() }); } return list; } } public class MyData { public string Data { get; set; } } } From the sample we can see how to get the data of each item. We can also set the visibility according to the item index. It's very flexible for us to decide what controls need to be displayed. For some scenarios there is another way, that is to use extra properties in the datasource item. Here's another sample: aspx: <asp:ScriptManager ID="ScriptManager1" runat="server" /> <cc1:ReorderList ID="ReorderList1" runat="server" DataSourceID="ObjectDataSource1" AllowReorder="false" > <ItemTemplate> <asp:TextBox ID="TextBox1" runat="server" Visible='<%# Eval("ShowTextBox")%>' Text='<%#Eval("Data") %>'></asp:TextBox> <asp:Label ID="Label1" runat="server" Visible='<%# Eval("ShowLabel")%>' Text='<%#Eval("Data") %>'></asp:Label> </ItemTemplate> </cc1:ReorderList> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="Select" TypeName="WebApplication2.BLL"></asp:ObjectDataSource> aspx.cs: namespace WebApplication2 { public partial class WebForm1 : System.Web.UI.Page { } public class BLL { public IEnumerable Select() { //Test List<MyData> list = new List<MyData>(); for (int i = 0; i < 10; i++) { list.Add(new MyData() { Data = i.ToString(), ShowLabel=i%2==0?true:false, ShowTextBox=i%3==0?true:false }); } return list; } } public class MyData { public string Data { get; set; } public bool ShowTextBox { get; set; } public bool ShowLabel { get; set; } } } Please have a try and let me know if it works. If you have further questions please feel free to ask. Regards, Allen Chen Microsoft Online Community Support Delighting our customers is our #1 priority. We welcome your comments and suggestions about how we can improve the support we provide to you. Please feel free to let my manager know what you think of the level of service provided. You can send feedback directly to my manager at: msd***@microsoft.com. ================================================== Get notification to my posts through email? Please refer to http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications. Note: MSDN Managed Newsgroup support offering is for non-urgent issues where an initial response from the community or a Microsoft Support Engineer within 2 business day is acceptable. Please note that each follow up response may take approximately 2 business days as the support professional working with you may need further investigation to reach the most efficient resolution. The offering is not appropriate for situations that require urgent, real-time or phone-based interactions. Issues of this nature are best handled working with a dedicated Microsoft Support Engineer by contacting Microsoft Customer Support Services (CSS) at http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx ================================================== This posting is provided "AS IS" with no warranties, and confers no rights. Hi Allen
Thanks for your suggestions. It looks like the right way to proceed. I´d like to take your suggestion further and I am wondering about extending the ReorderList control. It provides me with a lot of the functionality I need already and I´d like to add a couple more templates, for example a header and footer. Also I´d like to pre-populate the existing templates (ItemTemplate, EditItemTemplate, InsertItemTemplate) with controls based on the data source. The extended control must then only support a datasource of type List<CustomObject>. I have some questions: 1. Where do I add the logic for adding the custom controls to the ItemTemplate, EditItemTemplate, InsertItemTemplate? Where do I set visibility and add property values to the controls from the data source? 2. How should I add the new header and footer templates? 3. The extended control is going to render form controls which need their values collecting after saving. Should I handle this in the extended control? Can you tell me the best practice for doing this? 4. Should I throw an exception if the data source is not of the required type? Where is the best place to handle this? I´d appreciate any advice, suggestions, comments you can give me regarding this. Thanks again Andrew Hi Andrew,
I have wrote a demo that may help to solve most of your concern. Please try the following code first: Aspx: <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <cc1:MyReorderList runat="server" ID="MyReorderList1" SortOrderField="Priority"> <HeaderTemplate> <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox><asp:Button ID="Button2" runat="server" Text="Test Header" /> </HeaderTemplate> <FooterTemplate> <asp:Label ID="Label2" runat="server" Text="I'm a footer :)" BackColor="Pink"></asp:Label> </FooterTemplate> </cc1:MyReorderList> Aspx.cs: public class MyObject { public int Priority { get; set; } public bool Flag { get; set; } public string Name { get; set; } public string Address { get; set; } } public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { List<MyObject> list = new List<MyObject>(); for (int i = 0; i < 10; i++) { list.Add(new MyObject() { Priority = i }); } list[1].Address = "Address1"; list[1].Flag = true; list[3].Address = "Address3"; list[3].Name = "Allen"; list[5].Flag = true; this.MyReorderList1.ItemTemplate = new MyTemplate(typeof(MyObject), "Priority"); this.MyReorderList1.DataSource = list; this.MyReorderList1.DataBind(); } } public class MyTemplate : ITemplate { Type type; string FieldColName; public MyTemplate( Type t, string fieldname) { type = t; this.FieldColName = fieldname; } public void InstantiateIn(Control objContainer) { Panel p = new Panel(); Label lbl = new Label(); foreach (var item in MyReorderList.MyMapping) { Control c = Activator.CreateInstance(item.Value) as Control; if (c != null) { c.Visible = false; p.Controls.Add(c); } } p.Controls.Add(lbl); lbl.DataBinding += new EventHandler(lblHeader_DataBinding); objContainer.Controls.Add(p); } private void lblHeader_DataBinding(object sender, EventArgs e) { object bound_value_obj = null; Label lbl = (Label)sender; IDataItemContainer data_item_container = (IDataItemContainer)lbl.NamingContainer; foreach (var p in data_item_container.DataItem.GetType().GetProperties()) { Type propertytype = p.PropertyType; bound_value_obj = p.GetValue(data_item_container.DataItem, null); Type controltype = null; bool canfind = MyReorderList.MyMapping.TryGetValue(propertytype, out controltype); if (canfind) { lbl.Visible = false; foreach (Control c in lbl.Parent.Controls) { if (c.GetType() == controltype) { c.Visible = true; //add logic here if you want to set initial value //here is a sample if (controltype == typeof(CheckBox)) { if (bound_value_obj is bool) { ((CheckBox)c).Checked = (bool)bound_value_obj; } } if (controltype == typeof(Label)) { if (bound_value_obj != null) ((Label)c).Text = bound_value_obj.ToString(); else { ((Label)c).Text = "NULL"; } } //if you want more you can add extra logic } } } else { lbl.Text = bound_value_obj.ToString(); } } } } public class MyReorderList : ReorderList { public static Dictionary<Type, Type> MyMapping { get; private set; } static MyReorderList() { //add default mappings. MyMapping = new Dictionary<Type, Type>(); MyMapping.Add(typeof(string), typeof(Label)); MyMapping.Add(typeof(bool), typeof(CheckBox)); MyMapping.Add(typeof(int), typeof(Button)); } [DefaultValue((string)null), PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(RepeaterItem)), Browsable(false)] public virtual ITemplate HeaderTemplate { get; set; } [DefaultValue((string)null), PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(RepeaterItem)), Browsable(false)] public virtual ITemplate FooterTemplate { get; set; } protected override void Render(HtmlTextWriter writer) { Panel header=new Panel(); this.HeaderTemplate.InstantiateIn(header); header.RenderControl(writer); base.Render(writer); Panel footer = new Panel(); this.FooterTemplate.InstantiateIn(footer); footer.RenderControl(writer); } } About the code: 1. The footer and header is simply created via HeaderTemplate and FooterTemplate. In Render event we can create instance of the footer/header and render the HTML tags via RenderControl method. 2. To give user flexibility to change the mapping of the control and the type of the data I added a global mapping MyMapping in MyReorderList class. There're some predefined mappings added initially and users can add/remove them when using MyReorderList control. 3. We can add much more functionalities that can provide more flexibility. But to make it simple I opt to just provide the code above. You can see though I tried to make it as simple as possible it still involved a lot of code. Please try it to see if it's the effect you're looking for and feel free to let me know if you need further assistance. Regards, Allen Chen Microsoft Online Support Hi Andrew,
Have you tested my code? Is it what you need? Regards, Allen Chen Microsoft Online Community Support Hi Allen
Sorry it's taken me a while to reply to this. I thought I would just send you an update. I have used some of your suggestions to extend the ReorderList, adding new Header/Footer templates and applying a similar visibility technique but I decided that creating a new custom template for my application was a lot of work. Instead I created some custom controls which can work within the ReorderList, but also a Repeater and other controls if I need to. I do have a question regardin the ReorderList you may be able to help me with. I wonder if it's possible to change the size (height) of the ReorderTemplate to match the size of the ItemTemplate? At the moment if the ItemTemplates vary in size the ReorderTemplate is fixed whch looks a bit odd when dragging Items. If you have any ideas how I can get round this I'd appreciate it. Many thanks Andrew Hi Andrew,
The suggestion I could provide is, you can get the ClientID of the control in the ReorderTemplate. After that hook the client side onmousedown event to the control in the ItemTemplate. Then in the JavaScript function that handles onmousedown, change the size of the control in the ReorderTemplate to make it the same with that of the event sender. AjaxControlToolkit is following Microsoft Public License (Ms-PL), which is out of the support boundaries of our managed newsgroups. If you have further questions please post it to http://forums.asp.net/1022.aspx. It is not managed, but this forum will provide support for AjaxControlToolkit professionally. AjaxControlToolkit License: http://www.codeplex.com/AjaxControlToolkit/license MSDN Newsgroup Support Boundary: http://blogs.msdn.com/msdnts/archive/2006/11/08/msdn-service-introduction.as px Regards, Allen Chen Microsoft Online Support
Default Values being displayed in DetailsView
Gridview templaye button control SelectCommand with SelectParameters.Add UpdateProgress animated gif freezes in ajax postback RE: Gridview templaye button control Re: FTP download RE: SelectCommand with SelectParameters.Add Re: Databinding Syntax Not Working in ListView LayoutTemplate Master/Detail Page. using formview control |
|||||||||||||||||||||||