问题
I have a ListView that includes an EditItemTemplate and an InsertItemTemplate. The two forms share almost all of their markup. For example:
<asp:listview runat="server" ... >
<layouttemplate>...</layouttemplate>
<itemtemplate>
<p><%#Eval("Name")%></p>
<p><%#Eval("Title")%></p>
...
</itemtemplate>
<insertitemtemplate>
<p>Name: <asp:textbox runat=server text='<%#Bind("Name")%>' /></p>
<p>Title: <asp:textbox runat=server text='<%#Bind("Title")%>' /></p>
...
<asp:button runat=server commandname="Insert" text="Save" />
</insertitemtemplate>
<edititemtemplate>
<p>Name: <asp:textbox runat=server text='<%#Bind("Name")%>' /></p>
<p>Title: <asp:textbox runat=server text='<%#Bind("Title")%>' /></p>
...
<asp:button runat=server commandname="Update" text="Save" />
</edititemtemplate>
</asp:listview>
Of course, in reality there's a lot going on in the insert and edit templates (lots of fields, with formatting, validation, etc.), and I hate to have to maintain the same markup twice.
My first thought was to move all the shared markup to a user control (.ascx):
<insertitemtemplate>
<custom:myform runat=server />
<asp:button runat=server commandname="Insert" text="Save" />
</insertitemtemplate>
<edititemtemplate>
<custom:myform runat=server />
<asp:button runat=server commandname="Update" text="Save" />
</edititemtemplate>
Unfortunately, the two-way binding (text='<%#Bind("Foo")%>') only works one way when the form is in a user control (it doesn't persist the data from the controls back to the database).
An alternative would be to move all the shared markup to an include file. Server-side includes are a throwback to classic ASP, but they still work in ASP.NET and can be useful in situations like this, because the contents of the include file are treated just like markup that's right on the page.
But include files are still a little hokey, and have their disadvantages (e.g. VisualStudio isn't very comfortable with them). Is there an alternative?
回答1:
I've ended up making a custom ListView that makes this straightforward. If there is no InsertItemTemplate, then the EditItemTemplate is used for both:
Private Sub ListView_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
If Me.InsertItemTemplate Is Nothing Then
Me.InsertItemTemplate = Me.EditItemTemplate
End If
End Sub
I've also created a custom "save" button that switches its commandname between "Update" and "Insert" as appropriate:
Private Sub SaveLinkButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
Dim _ListView As Controls.ListView = GetListView()
If _ListView IsNot Nothing Then
If Me.BindingContainer Is _ListView.EditItem Then
Me.CommandName = "Update"
Else
Me.CommandName = "Insert"
End If
End If
End Sub
(The GetListView
function above just walks up the button's parents until it finds a ListView.)
That's it - hope this is helpful to someone.
回答2:
I'm very late to the party, but for anyone looking for a declarative solution, I ended up doing the following (control
is my FormView
):
if (control.EditItemTemplate == null)
{
control.EditItemTemplate = control.InsertItemTemplate;
}
And for the template:
<InsertItemTemplate>
... template ...
<asp:LinkButton Text="Insert" CommandName="Insert" runat="server"
Visible='<%# Container.ItemType == ListViewItemType.InsertItem %>' />
<asp:LinkButton Text="Update" CommandName="Update" runat="server"
Visible='<%# Container.ItemType == ListViewItemType.DataItem %>' />
<asp:LinkButton Text="Cancel" CommandName="Cancel" runat="server"
Visible='<%# Container.ItemType == ListViewItemType.DataItem %>' />
</InsertItemTemplate>
Where the interesting bit is obviously: Container.ItemType == ListViewItemType.DataItem
(and others). This correctly sets the visibility of the buttons according to the template type.
来源:https://stackoverflow.com/questions/2184757/asp-net-listview-with-identical-markup-in-edititemtemplate-and-insertitemtemplat