How to bind an Asp.NET details view to an object with a List<string> property
-
19-09-2019 - |
Question
I have the following example entity object
class Entity
{
public string Name { get; set; }
public IList<string> Fields { get; set; }
}
Now I have a details view bound to a datagrid and both can display/edit the name property fine, but I want to be able to edit the fields property as well.
I was hoping to use a multi-line textbox to do this. So each line would correspond to an item in the Fields list. But I am having an issue how to bind the list to the textbox so each item is on a new line. I don't think I have an issue of getting the details out and putting them back into the object to save afterwards since I do this manually.
So the question is, Is there a way I can perform a custom bind on the textbox in the details view so each IList item is on a separate line?
Solution
Right the answer seems to be as follows:
In the code bind the aspx page create a method as below:
public string CustomBind(object data)
{
if(data is List<string>)
{
List<string> list = data as List<string>;
return string.Join("\n", list.ToArray();
}
}
Then in your aspx page you would do the following on the textbox to bind it.
<asp:Textbox TextMode="MultiLine" Text='CustomBind(Eval("MyList"))'></asp:TextBox>
I want to thank Dave for providing this answer in the Newbie ASP.NET Eval question question.
OTHER TIPS
What you are after is something like a nested ListView. Nesting these things gets messy but this should work:
<asp:GridView runat="server" ID="EntityGridView" AutoGenerateColumns="False"
EditIndex="0" OnRowUpdating="EntityGridView_RowUpdating">
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:Label ID="NameLabel" runat="server" Text='<%# Bind("Name") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="NameTextBox" runat="server" Text='<%# Bind("Name") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:GridView runat="server" DataSource='<%# Eval("Fields") %>'/>
</ItemTemplate>
<EditItemTemplate>
<asp:ListView runat="server" DataSource='<%# Eval("Fields") %>' ID="FieldListView">
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<asp:TextBox Text='<%# Container.DataItem %>' runat="server" ID="FieldValue"/><br />
</ItemTemplate>
</asp:ListView>
</EditItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowEditButton="True" />
</Columns>
</asp:GridView>
And your update method will look like:
protected void EntityGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
var updatedEntity = new Entity {Fields = new List<string>()};
var row = EntityGridView.Rows[e.RowIndex];
var nameTextBox = (TextBox) row.FindControl("NameTextBox");
updatedEntity.Name = nameTextBox.Text;
var fieldListView = (ListView) row.FindControl("FieldListView");
foreach (var dataItem in fieldListView.Items)
{
var fieldValueTextBox = (TextBox)dataItem.FindControl("FieldValue");
updatedEntity.Fields.Add(fieldValueTextBox.Text);
}
// Do your save etc here
}
Then you just bind your list of entities to the GridView.
try something like
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(string[] Fields)
{
// do something with Fields array
}
You can also use the Extension Methods so you don't explicitly have to make the methods for this task on all of your pages.
<asp:TextBox TextMode="MultiLine" ID="txtQuotes" runat="server" Text='<%# ((List<String>) Eval("Quotes")).ToMultiLine() %>' />
public static class ExtensionMethods
{
public static string ToMultiLine(this List<String> list)
{
return String.Join("\n", list.ToArray());
}
}