The Personal Website Starter Kit is a great resource for getting up and
running with asp.net 2.0 beta. I've been using it to check out some features
while waiting for other projects to get to a point where I feel like I can
contribute more than just criticism (sorry y'all :) That said, the default.aspx
page comes with a FormsView that rotates pictures from your PSKit albums, but
everything else is static content! That is, you're greeted on the front page
with something like:
Welcome to my Website!
On this site you will find lorem ipsum dolor sit amet...
Earlier, I had tried using one of the new data controls in asp.net -
namely the FormView. I ran into a few issues with this control, mostly having to
do with having to know what ID I was using in the database to set or edit the
FormView's contents - I'm sure I could have worked out a way to set the ID to
use in some clever way, but then I looked at the actual content that comes stock
with the PSKit and it hit me...
A DataList.
It's already separated by a horizontal rule - all I really need is to
bind a good old DataList to a couple of database entries and I've got something
that I can update, oh, say twice a year or whatever. heh.
I used a similar table structure to the one from before:
Content
ContentID
Heading
Content
IsVisible
I had to actually write code (gasp!) to get it working the way I
wanted it to, but it was pretty stock stuff thankfully. I just set up a
SqlDataSource pointing to this table's CRUD procedures:
<asp:SqlDataSource ID="SqlDataSource1"
runat="server"
ConnectionString="<%$ ConnectionStrings:Personal %>"
ProviderName="System.Data.SqlClient"
SelectCommand="GetContents"
SelectCommandType="StoredProcedure"
DeleteCommand="RemoveContent"
DeleteCommandType="StoredProcedure"
InsertCommand="AddContent"
InsertCommandType="StoredProcedure"
UpdateCommand="EditContent"
UpdateCommandType="StoredProcedure">
<DeleteParameters>
<asp:Parameter Name="Content_ID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="Content_ID" Type="Int32" />
<asp:Parameter Name="Heading" Type="String" />
<asp:Parameter Name="Content" Type="String" />
<asp:Parameter Name="IsVisible" Type="Boolean" />
</UpdateParameters>
<InsertParameters>
<asp:Parameter Direction="InputOutput" Name="Content_ID" Type="Int32" />
<asp:Parameter Name="Heading" Type="String" />
<asp:Parameter Name="Content" Type="String" />
<asp:Parameter Name="IsVisible" Type="Boolean" />
</InsertParameters>
</asp:SqlDataSource>
Then the DataList itself:
<asp:DataList ID="DataList1"
runat="server"
DataSourceID="SqlDataSource1"
Width="100%"
OnCancelCommand="DataList1_CancelCommand"
OnEditCommand="DataList1_EditCommand"
OnUpdateCommand="DataList1_UpdateCommand"
OnDeleteCommand="DataList1_DeleteCommand"
OnItemCommand="DataList1_ItemCommand"
RepeatLayout="Flow" >
<ItemTemplate>
<asp:Panel ID="contentPanel"
runat="server"
Visible='<%# Eval("IsVisible") %>'>
<h3><asp:Label ID="HeadingLabel"
runat="server"
Text='<%# Eval("Heading") %>'></asp:Label></h3>
<asp:Label ID="ContentLabel"
runat="server"
Text='<%# Eval("Content") %>'></asp:Label>
<asp:HiddenField ID="hdnContentID"
runat="server"
Value='<%# Eval("Content_ID") %>' />
</asp:Panel>
<asp:Panel ID="Panel1"
Visible='<%# User.IsInRole("Administrators") %>'
runat="server" Height="50px" Width="125px">
<asp:LinkButton ID="LinkButton3"
runat="server"
CommandName="edit">Edit</asp:LinkButton>
<asp:LinkButton ID="LinkButton4"
runat="server"
CommandName="delete">Delete</asp:LinkButton></asp:Panel>
</ItemTemplate>
<SeparatorTemplate>
<hr />
</SeparatorTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtHeading"
runat="server"
Text='<%# Bind("Heading") %>'></asp:TextBox>
<asp:CheckBox ID="chkVisible"
runat="server"
Checked='<%# Bind("IsVisible") %>'
Text="Visible" />
ContentID:
<asp:Label ID="lblContentID"
runat="server"
Text='<%# Eval("Content_ID") %>'></asp:Label>
<asp:TextBox ID="txtContent"
runat="server"
Columns="40" Rows="20"
Text='<%# Bind("Content") %>'
TextMode="MultiLine"></asp:TextBox>
<br />
<br />
<asp:LinkButton ID="LinkButton1"
runat="server"
CommandName="update">Update</asp:LinkButton>
<asp:LinkButton ID="LinkButton2"
runat="server"
CausesValidation="False"
CommandName="cancel">Cancel</asp:LinkButton>
<asp:LinkButton ID="LinkButton5"
runat="server"
CommandName="add">Create as New</asp:LinkButton>
</EditItemTemplate>
</asp:DataList>
Several points of interest in the DataList declaration:
-
No more pesky DataBinder.Eval(Container.DataItem, "field") syntax - much
leaner and meaner Eval() syntax for one-way binding.
-
Two-way binding happens via the Bind() syntax - notice that Bind() only
happens in the EditItemTemplate, since the ItemTemplate is readonly.
-
I'm only showing the edit/delete buttons based on what role the current
user is in. I wasn't sure if this (#
User.IsInRole("Administrators")) would work at first because it's
deceptively simple. But yeah, it does work. Works great!
-
I did most of this visually - there is no longer a reason to fear the
designer in asp.net (thanks Venus team!)
-
I had to disable Page input validation because I want the Content to
contain html, and by default, it don't like that.
As for the codebehind, I guess I could have refactored it a little bit, but
since this is not a mission-critical application (it is just a personal site,
after all!) I just went the easy route and duplicated a lot of code. Probably
the best thing to do would be to handle just the ItemCommand because there is no
default handler for add and use a clever mix of a switch statement and
defaulting the value of EditItemIndex to -1. But this isn't about best
practices, it's about getting the stuff to work, ya know? Anyway, here's the
code:
1 protected void DataList1_CancelCommand(object source, DataListCommandEventArgs e)
2 {
3 this.DataList1.EditItemIndex = -1;
4 this.DataList1.DataBind();
5 }
6 protected void DataList1_UpdateCommand(object source, DataListCommandEventArgs e)
7 {
8 string heading = ((TextBox)e.Item.FindControl("txtHeading")).Text;
9 string content = ((TextBox)e.Item.FindControl("txtContent")).Text;
10 string isvisible = ((CheckBox)e.Item.FindControl("chkVisible")).Checked.ToString();
11 string id = ((Label)e.Item.FindControl("lblContentID")).Text;
12
13 this.SqlDataSource1.UpdateParameters["Content_ID"].DefaultValue = id;
14 this.SqlDataSource1.UpdateParameters["Heading"].DefaultValue = heading;
15 this.SqlDataSource1.UpdateParameters["Content"].DefaultValue = content;
16 this.SqlDataSource1.UpdateParameters["IsVisible"].DefaultValue = isvisible;
17
18 this.SqlDataSource1.Update();
19
20 this.DataList1.EditItemIndex = -1;
21 this.DataList1.DataBind();
22 }
23 protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e)
24 {
25 string id = ((HiddenField)e.Item.FindControl("hdnContentID")).Value;
26 this.SqlDataSource1.DeleteParameters["Content_ID"].DefaultValue = id;
27
28 this.SqlDataSource1.Delete();
29
30 this.DataList1.EditItemIndex = -1;
31 this.DataList1.DataBind();
32 }
33 protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e)
34 {
35 switch (e.CommandName)
36 {
37 case "add":
38 string heading = ((TextBox)e.Item.FindControl("txtHeading")).Text;
39 string content = ((TextBox)e.Item.FindControl("txtContent")).Text;
40 string isvisible = ((CheckBox)e.Item.FindControl("chkVisible")).Checked.ToString();
41
42 this.SqlDataSource1.InsertParameters["Heading"].DefaultValue = heading;
43 this.SqlDataSource1.InsertParameters["Content"].DefaultValue = content;
44 this.SqlDataSource1.InsertParameters["IsVisible"].DefaultValue = isvisible;
45
46 this.SqlDataSource1.Insert();
47
48 this.DataList1.EditItemIndex = -1;
49 this.DataList1.DataBind();
50 break;
51 }
52 }
This is the quickest way I could figure out to make things work, and yeah, it
does work. So, there you have it - even though there are only two items
currently in the table, it's very easy to add content via in-place editing and
change what is currently there as well. You can view it live over at www.bluefenix.net.
[ Currently Playing : Voices - Godsmack - Other Side (3:44)
]