Adapting ReorderList WebControl for rendering dynamic html

Discussion in 'ASP .Net Web Controls' started by Andrew Jocelyn, Jan 5, 2009.

  1. Hi

    I 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
     
    Andrew Jocelyn, Jan 5, 2009
    #1
    1. Advertising

  2. 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:
    .

    ==================================================
    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.
     
    Allen Chen [MSFT], Jan 6, 2009
    #2
    1. Advertising

  3. 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
     
    Andrew Jocelyn, Jan 7, 2009
    #3
  4. 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
     
    Allen Chen [MSFT], Jan 9, 2009
    #4
  5. Hi Andrew,

    Have you tested my code? Is it what you need?

    Regards,
    Allen Chen
    Microsoft Online Community Support
     
    Allen Chen [MSFT], Jan 13, 2009
    #5
  6. 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
     
    Andrew Jocelyn, Feb 2, 2009
    #6
  7. 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
     
    Allen Chen [MSFT], Feb 3, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mark Micallef
    Replies:
    0
    Views:
    645
    Mark Micallef
    Apr 5, 2007
  2. Andrew Jocelyn
    Replies:
    2
    Views:
    1,527
    Allen Chen [MSFT]
    Apr 27, 2009
  3. Nizam

    Reorderlist Style

    Nizam, May 29, 2009, in forum: ASP .Net
    Replies:
    1
    Views:
    813
    Alexey Smirnov
    May 31, 2009
  4. Mark Micallef
    Replies:
    0
    Views:
    215
    Mark Micallef
    Apr 5, 2007
  5. Frenske

    Adding a control inside a reorderlist

    Frenske, Jun 14, 2007, in forum: ASP .Net Web Controls
    Replies:
    0
    Views:
    145
    Frenske
    Jun 14, 2007
Loading...

Share This Page