What is best way to store controls and add control

2019-07-31 08:19发布

问题:

I have a generic form which shows default controls. I'm trying to build a form queue where if we have a client that wants extra data, I would like to store asp.net controls required to capture data for each client and load them dynamically along with default form.

Does anybody know or direct me to a architecture/solution to implement this[store the forms and load and add them dynamically to existing form and retrieve data from them passed].

My initial thought was to use xml file for each client that wants extra data than existing static form data and load this xml based on file name(which matches client name) and add it to a content-place-holder and then loop through page on button click to get data from those dynamic fields.

回答1:

This XML file could work for this example:

<?xml version="1.0"?>
<!-- Custom fields per tenant/form -->
<Customers>
  <IBM>
    <Employee>
      <Field Id="FirstName" Label="First name" />
      <Field Id="LastName" Label="Last name" />
    </Employee>
  </IBM>
</Customers>

Start off by configuring an XmlDataSource on the page. You can swap this for an SqlDataSource if you plan to store the form definition in the database along with the customer instead of in XML files.

<asp:XmlDataSource ID="CustomFields" runat="sever" 
  DataFile="~/App_Data/CustomFields.config"
  XPath="//Customers/IBM/Employee">
</asp:XmlDataSource>

In this case we would use one XML file, for each customer there would be a node, and for each type of form another node. In this example IBM is the customer, and Employee is the form. Of course the XPath attribute needs to be set dynamically:

protected void Page_Load()
{
  if(!Page.IsPostBack)
  {
    CustomFields.XPath = String.Format("//Customers/{0}/{1}", CustomerName, FormName);
  }
}

Now you can data bind part of the form using a ListView, using the attributes in the XML to display a TextBox control for each field:

<asp:ListView ID="DynamicFields" runat="server"
  DataSourceID="CustomFields"
  ItemPlaceHolderID="Item">
  <LayoutTemplate>
    <fieldset>
      <legend>Custom fields</legend>
      <asp:PlaceHolder ID="Item" runat="server" />
    </fieldset>
  </LayoutTemplate>
  <ItemTemplate>
    <div>
      <asp:Label runat="server"
        Text='<%# XPath("Field/@Label") %>'
        AssociatedControlID="Field" />
      <br />
      <asp:TextBox ID="Field" runat="server" 
        data-field-id='<%# XPath("Field/@Id") %>' />
    </div>
  </ItemTemplate>
</asp:ListView>

In your code behind you can now retrieve the values for each field and map them back using the data-field-id attribute:

protected void Save_Click(object sender, EventArgs e) 
{
  foreach(ListViewItem item in DynamicFields.Items)
  {
    TextBox field = item.FindControl("Field") as TextBox;
    string id = field.Attributes["data-field-id"];
    string value = field.Text;
  }
}

Of course, it becomes more complex when you also want to load data into the fields for edit forms, but this is just a general approach based on your own suggestion.

Some things to consider for storage are mapping to a special table with columns for each type of data (strings, numbers, dates etc.). For that, you would need to annotate your XML with the type of data, and validate input based on that.

<Field Id="FirstName" Label="First Name" Type="String" />
<Field Id="DateOfBirth" Label="Date of birth" Type="DateTime" />

If you don't need that, then you could consider serializing all the values to a single string (JSON?) for storing in a single column in the database. This makes it almost impossible to run queries on the data though.

{ "FirstName": value, "LastName": value }


回答2:

Add all the controls to the form. Hide the optional ones and show them as required.



回答3:

I suggest use binding, dynamicly create your user control and bind sub control to a data of your queue(with binding source), and after post-back get data from binding source and update in queue.