I know the title might make my question look like a duplicate so please read the complete question first.
I have 3 dropdowns in my webform and based on those parameters the data is retrieved from the database and my gridview is populated. What I need is that once a result is displayed, if the user changes the parameters, the new retrieved data should be displayed below the old data. But currently my gridview is refreshing entirely and only the data based on new parameters is displayed.
I have read that one way is to use viewstate but I dont understand what it is. Can someone please help? Thank you.
Ok, so this is a difficult question. It is rather easy to filter, and have a cumulative filter.
So, say we have this screen:
And lots more rows.
So, I can say lets filter by a city.
So this:
Note how we do allow multiple city in the multi-select drop down.
So, I now have this:
Now, lets select those ONLY with a description.
So this:
And then say only active ones. So, this:
So, above is quite easy to setup. Note how any option NOT selected is left out of the critera.
but, a BIG problem exists in the above.
What happens if I want Active from say B.C. but NOT active from Alberta???
I can't do that, and hence your problem.
What we could do however is add a button to above to SAVE the resulting filter, and put the "list" of filters say into a list box or collection.
we then have a search button to search on our collection of filters.
Let me see if this can work - I'll add to above a "box" or collection of each filter.
I would think a union query with distinct row for each filter would do the trick.
So, above example is not too hard - a "cumulative" filter. In fact, the code patter for 2 or 15 filters is quite easy to do here.
However, adding up separate filter requests and combine them? That is somewhat difficult to do.
Edit: Multiple filters
so, while in above, I could say filter by city and get all active, but THEN I want to filter by another city, and get all NON active!!!
That's the problem here.
So, we would have to add code to SAVE the filter. And the HUGE problem with that is how then do we save each filter to "add up" each filter set we want?
We could try and save the raw SQL, but such SQL would be subject to sql injection, and we want to always use parameters.
So, we can and could adopt a design in which we SAVE the resulting SqlCommand object. And then merge the results.
So, now our UI becomes like this:
Lets grab and filter all those from city Edmonton, but Active,
so, this:
We now hit save filter and this:
And now we filter by say City = Banff, but don't care about active or not.
So we have this:
We then save that filter - and now we have this:
I now hit the filter button below the list of filters, and we get this:
So, how does this code work?
Well, I simple saved the Sqlcommand object to a collection (list), and thus combine the results.
So, first our markup at the top for the filter stuff.
<h4>Filters</h4>
<div style="float:left">
<asp:Label ID="Label1" runat="server" Text="Search Hotel"></asp:Label>
<br />
<asp:TextBox ID="txtHotel" runat="server"></asp:TextBox>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label2" runat="server" Text="Search City"></asp:Label>
<br />
<asp:TextBox ID="txtCity" runat="server"></asp:TextBox>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label3" runat="server" Text="Must Have Description"></asp:Label>
<br />
<asp:CheckBox ID="chkDescripiton" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label4" runat="server" Text="Show only Active Hotels"></asp:Label>
<br />
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdSearch" runat="server" Text="Search" CssClass="btn" OnClick="cmdSearch_Click"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdClear" runat="server" Text="Clear Fitler" CssClass="btn" OnClick="cmdClear_Click"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdTest" runat="server" Text="Save Filter"
CssClass="btn" OnClick="cmdTest_Click"
OnClientClick="return myfilterprompt()"
/>
<asp:HiddenField ID="HFilterName" runat="server" ClientIDMode="Static"/>
<script>
function myfilterprompt() {
sFilter = ""
sFilter = prompt('Enter name for filter ')
if ( (sFilter === null) || (sFilter === "") ){
return false
}
$('#HFilterName').val(sFilter)
return true
}
</script>
</div>
<div style="float:left;margin-left:30px;width:190px">
<asp:ListBox ID="lstFilters" runat="server" Width="100%" Height="100px"
DataTextField="sFilterName" >
</asp:ListBox>
<asp:Button ID="cmdMultiFilter" runat="server" Text="Filter"
CssClass="btn" OnClick="cmdMultiFilter_Click" style="float:left" />
<asp:Button ID="cmdMultiClear" runat="server" Text="Clear"
CssClass="btn" OnClick="cmdMultiClear_Click" style="float:right"/>
</div>
then below above is our grid:
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID"
CssClass="table" Width="60%" ShowHeaderWhenEmpty="true">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:BoundField DataField="Active" HeaderText="Active" />
</Columns>
</asp:GridView>
So, code to load:
List<MyFilter> MyFilters = new List<MyFilter>();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
SqlCommand cmdSQL = new
SqlCommand("SELECT * FROM tblHotels WHERE ID = 0");
LoadGrid(cmdSQL);
Session["MyFilters"] = MyFilters;
}
else
MyFilters = (List<MyFilter>)Session["MyFilters"];
}
public void LoadGrid(SqlCommand cmdSQL)
{
DataTable rstData = MyRstP(cmdSQL);
GridView1.DataSource = rstData;
GridView1.DataBind();
}
And now our search button:
protected void cmdSearch_Click(object sender, EventArgs e)
{
SqlCommand cmdSQL = GetMyCommand();
LoadGrid(cmdSQL);
}
SqlCommand GetMyCommand()
{
string strSQL = "SELECT * FROM tblHotels ";
string strORDER = " ORDER BY HotelName";
string strFilter = "";
SqlCommand cmdSQL = new SqlCommand();
if (txtHotel.Text != "")
{
strFilter = "(HotelName like #HotelName + '%')";
cmdSQL.Parameters.Add("#HotelName", SqlDbType.NVarChar).Value = txtHotel.Text;
}
if (txtCity.Text != "")
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(City Like #City + '%') ";
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = txtCity.Text;
}
if (chkActiveOnly.Checked)
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(Active = 1)";
}
if (chkDescripiton.Checked)
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(Description is not null)";
}
if (strFilter != "") strSQL += " WHERE " + strFilter;
strSQL += strORDER;
cmdSQL.CommandText = strSQL;
return cmdSQL;
}
And now our save the filter button code:
protected void cmdTest_Click(object sender, EventArgs e)
{
MyFilter OneFilter = new MyFilter();
OneFilter.sFilterName = HFilterName.Value;
OneFilter.cmdSQL = GetMyCommand();
MyFilters.Add(OneFilter);
lstFilters.DataSource = MyFilters;
lstFilters.DataBind();
}
public class MyFilter
{
public string sFilterName { get; set; }
public SqlCommand cmdSQL = new SqlCommand();
}
And our multi-filter code button.
Now, for large data sets - not a great idea, but a start:
protected void cmdMultiFilter_Click(object sender, EventArgs e)
{
List<DataTable> MyTables = new List<DataTable>();
foreach (MyFilter OneFilter in MyFilters)
{
DataTable rstDT = MyRstP(OneFilter.cmdSQL);
MyTables.Add(rstDT);
}
DataTable rstData = MyTables[0];
for (int i = 1;i < MyTables.Count;i++)
{
rstData.Merge(MyTables[i]);
}
GridView1.DataSource = rstData;
GridView1.DataBind();
}
so, you can build list up of "filters" and display them in a listbox and then have a filter button that merges all of the filtering.
And one more helper routine I used:
public DataTable MyRstP(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
These systems can be really nice. Often a group of managers will say, lets grab all customers from west coast. Yuk - too many. Ok, only those with purchases in last 2 months - ah, that's nice.
then they say, lets get all customers who never purchased anything, but from the south - and add those to the list - but only active on our mailing list.
So, this type of slice and dice - get some of those, and then get some of these, and then combine them?
This type of business query system and being able to combine these, and those, and them, and then toss in a few more? Often they will keep going say until such time they get say 10,000 results (which happens to be how many catalogs they have left they would like to send out).
So, I solved my problem by using a little outside the box thinking. I am posting it here for anyone visiting this question or having a same problem in the future could see this:
So what I did is that I extracted the data from the database based on the parameters selected by the user from the dropdowns. In the database, I had created a temp table to store the extracted temporarily. So I inserted the data into that temporary table and used that table to populate the gridview. I had to add a reset button, when the user clicked it the all the data is deleted from the temp table and also the page reset to its default with gridview not visible and dropdowns having no selection.
Related
I have 3 different textboxes for serials. And when I click the button I want to save them for each row in database table.
Textbox1.Text="HP" ==> STOCKID
Textbox2.Text="İ5" ==> MODEL
Textbox3.Text="3" ==> QUANTITY
Textbox4.Text="11231231"; ==> SERIAL-1
Textbox5.Text="11231231"; ==> SERIAL-2
Textbox6.Text="11231231"; ==> SERIAL-2
Then Button click event.
Result should be as below.
FIRST GRIDVIEW
STOKID
MODEL
QUANTİTY
HP
I5
3
SECOND GRIDVIEW
STOKID
MODEL
SERIALS
DELETEBUTTON
HP
I5
32165161
BUTTON
HP
I5
12313223
BUTTON
HP
I5
16516516
BUTTON
When I delete from serials one bye one, the first Gridview QTY should decrease one for each serials. Is it possible?
I use store procedure during insert to data for first gridview. But for second one I don't know how to use a loop for textboxes and add to database different serials(textboxes values).
Ok, so say this markup:
We have Stokkid, model, and then have 3 optional serial num boxes
(if they are left blank - we don't add).
So, this markup:
The boxes, and add button:
<div style="float: left">
<h4>Stokid</h4>
<asp:TextBox ID="txtStokID" runat="server"></asp:TextBox>
</div>
<div style="float: left;margin-left:20px">
<h4>Model</h4>
<asp:TextBox ID="txtModel" runat="server"></asp:TextBox>
</div>
<div style="float: left;margin-left:20px">
<h4>Serial 1</h4>
<asp:TextBox ID="txtS1" runat="server"></asp:TextBox>
</div>
<div style="float: left;margin-left:20px">
<h4>Serial 2</h4>
<asp:TextBox ID="txtS2" runat="server"></asp:TextBox>
</div>
<div style="float: left;margin-left:20px">
<h4>Serial 3</h4>
<asp:TextBox ID="txtS3" runat="server"></asp:TextBox>
</div>
<div style="float: left;margin-left:20px;margin-top:20px">
<asp:Button ID="cmdSave" runat="server" Text="Save/Add" CssClass="btn"
OnClick="cmdSave_Click"
/>
</div>
<div style="clear:both" ></div>
And right below that, 2 grids, the first totals gv, and then the data we have gv.
So, this:
<h3>Counts</h3>
<asp:GridView ID="GVCounts" runat="server" CssClass="table"
width="40%" ShowHeaderWhenEmpty="True" >
</asp:GridView>
<h3>Items</h3>
<asp:GridView ID="GridView1" runat="server" CssClass="table"
width="40%" ShowHeaderWhenEmpty="True" >
</asp:GridView>
And now our code to load up the above:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
// load up "counts" grid
string strSQL =
#"SELECT Stokid, Model, count(*) as QTY FROM tblSerials
GROUP BY Stokid, Model";
GVCounts.DataSource = MyRst(strSQL);
GVCounts.DataBind();
// Load up existing data grid
strSQL =
#"SELECT Stokid, Model, Serials FROM tblSerials ORDER BY ID";
GridView1.DataSource = MyRst(strSQL);
GridView1.DataBind();
}
So, only part left is the "add new data button"
That code is this:
protected void cmdSave_Click(object sender, EventArgs e)
{
// save (add) one row for each serial number,
// if no serial - then don't add
DataTable dt = MyRst("SELECT * FROM tblSerials WHERE ID = 0");
DataRow MyAddRow = dt.NewRow();
MyAddRow["Stokid"] = txtStokID.Text;
MyAddRow["Model"] = txtModel.Text;
MyAddRow["Serials"] = txtS1.Text;
dt.Rows.Add(MyAddRow);
if (txtS2.Text != "")
{
MyAddRow = dt.NewRow();
MyAddRow["Stokid"] = txtStokID.Text;
MyAddRow["Model"] = txtModel.Text;
MyAddRow["Serials"] = txtS2.Text;
dt.Rows.Add(MyAddRow);
}
if (txtS3.Text != "")
{
MyAddRow = dt.NewRow();
MyAddRow["Stokid"] = txtStokID.Text;
MyAddRow["Model"] = txtModel.Text;
MyAddRow["Serials"] = txtS3.Text;
dt.Rows.Add(MyAddRow);
}
// send/save all rows to database
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST5))
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT * FROM tblSerials", conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
da.Update(dt);
}
}
// Update counts and display
LoadData();
}
so, the result is now this:
Now, we do probably want to setup a delete button.
so, that means our "cheat" life and easy GV of data?
Well, we have to give it a bit more effort, love and care.
We need the database PK id, and we want that delete button.
And since the delete button can be a danger, then it should confirm.
So, we have to update our GV a bit, bite the bullet and use some templating. but, it is not much.
And lets use a boot-strap icon - they should be part of any most recent project by defualt. But BE warned, after boottrap 4, the later versions (due to some copyright/lawsuit, bootstrap does not include the glyph-icons).
Anyway, I COULD use a plain jane asp.net button in the gv for delete, but lets use standard html button - I ONLY use the html one, since I wanted the cute icon. Probably better for you to use a image button.
(code is much the same either way).
So, our 2nd gv now looks like this:
<h3>Items</h3>
<asp:GridView ID="GridView1" runat="server" CssClass="table table-hover"
width="40%" ShowHeaderWhenEmpty="True" DataKeyNames="ID"
AutoGenerateColumns="False" >
<Columns>
<asp:BoundField DataField="STOKID" HeaderText="STOKID" />
<asp:BoundField DataField="MODEL" HeaderText="MODEL" />
<asp:BoundField DataField="serials" HeaderText="serials" />
<asp:TemplateField HeaderText="Delete" ItemStyle-Width="80px" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<button id="cmdDelete" runat="server" class="btn"
onclick="if (!confirm('Delete')) return false;"
onserverclick="cmdDel_ServerClick" >
<span aria-hidden="true" class="glyphicon glyphicon-trash"></span>
</button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And the code to load up this gv is now:
void LoadData()
{
// load up "counts" grid
string strSQL =
#"SELECT Stokid, Model, count(*) as QTY FROM tblSerials
GROUP BY Stokid, Model";
GVCounts.DataSource = MyRst(strSQL);
GVCounts.DataBind();
// Load up existing data grid
strSQL = #"SELECT * FROM tblSerials ORDER BY ID";
GridView1.DataSource = MyRst(strSQL);
GridView1.DataBind();
}
And our delete code is this:
protected void cmdDel_ServerClick(object sender, EventArgs e)
{
HtmlButton btn = (HtmlButton)sender;
GridViewRow gRow = (GridViewRow)btn.NamingContainer;
int PKID = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
string strSQL = "DELETE FROM tblSerial WHERE ID = {PKID}";
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST5))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
cmdSQL.ExecuteNonQuery();
}
}
// update count and items gv
LoadData();
}
So, now we see, get this for a delete:
Edit2: The Myrst routine
In a few places in above, I also used this helper routine, since I get VERY tired VERY fast having to write code each and every time I want some data, so, I wrote and use this routine:
DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST5))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
It handy for filling out a gridview, dropdown list etc.
I have just a simple message page which consists of From: Text: and a Submit button, then I have another page, which contains nothing, it's my "Message Board" the most recent posted message goes on top of the board, both are aspx pages with master page.
I have a SQL DB, I'm already assuming there will be a table with From: Message:(with varchar i think), but what i don't understand how it will get inserted into the messageboard page in a most recent to oldest list fashion.
Message.aspx - From: Text: Submit
MessageBoard.aspx - just a div , messages submitted will appear here in a drop down list
I want it to be super simple no cool features, only "Submit the message" -> "Appears on MessageBoard.aspx to everyone",
and that's it
Ok, there are seveal moving parts.
Assuming you have SQL server running. Assuming you have a valid conneciton?
Ok, then on the post a new message page, you have this markup:
<h3>Post a message</h3>
<h4>enter your name</h4>
<asp:TextBox ID="txtName" runat="server" Width="250px"></asp:TextBox>
<br />
<h4>Enter your message</h4>
<asp:TextBox ID="txtMsg" runat="server" Height="185px" Width="520px"
TextMode="MultiLine" Font-Size="Large" style="border-radius:20px;border:solid 2px"
></asp:TextBox>
<br />
<br />
<asp:Button ID="cmdNewMessage" runat="server" Text="Post Message" CssClass="btn"
OnClick="cmdNewMessage_Click" />
And code behind looks like this:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void cmdNewMessage_Click(object sender, EventArgs e)
{
string strSQL =
#"INSERT INTO tblMessages (UName, Message, MessageDate)
VALUES (#UName, #Message, #MessageDate)";
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
cmdSQL.Parameters.Add("#UName", SqlDbType.NVarChar).Value = txtName.Text;
cmdSQL.Parameters.Add("#Message",SqlDbType.NVarChar).Value = txtMsg.Text;
cmdSQL.Parameters.Add("#MessageDate", SqlDbType.NVarChar).Value = DateTime.Now;
cmdSQL.ExecuteNonQuery();
}
}
Response.Redirect("MessageBoard.aspx");
}
So, it looks like this:
when you hit post message, we jump to this page, and markup:
<asp:Button ID="cmdPost" runat="server"
Text="Post a new message"
CssClass="btn" OnClick="cmdPost_Click" />
<br />
<br />
<h2>Messages</h2>
<asp:GridView ID="GridView1" runat="server" Width="50%"
AutoGenerateColumns="False" DataKeyNames="ID" >
<Columns>
<asp:BoundField DataField="UName" HeaderText="Posted by" />
<asp:BoundField DataField="MessageDate" HeaderText="At" ItemStyle-Width="180px" />
<asp:TemplateField HeaderText="Message" >
<ItemTemplate>
<asp:Textbox ID="txtMsg" runat="server" TextMode="MultiLine" Width="100%"
Text='<%# Eval("Message") %>'
Height='<%# (Regex.Matches(Eval("Message").ToString() , System.Environment.NewLine).Count + 1) * 30 %>'
>
</asp:Textbox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And code is:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL = "SELECT * FROM tblMessages ORDER BY MessageDate DESC";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
GridView1.DataSource = cmdSQL.ExecuteReader();
GridView1.DataBind();
}
}
}
protected void cmdPost_Click(object sender, EventArgs e)
{
Response.Redirect("NewMessage.aspx");
}
And we now see/have this:
You don't explain what you mean by "what i don't understand how it will get inserted into the messageboard page in a most recent to oldest list fashion", so I can only guess.
When a new message is posted, you insert it into the database, including a DateTime column. Your message list page then just grabs the latest nn messages, ordered by newest first.
I'm assuming that you know how to do that. If not, do some reading about Entity Framework Core, as that provides a very good way of handling databases.
So, in princple, your question is no more complex than that. However, there are many variations on this, such as having the message list updated in real time, for which you should use SignalR, but without more specific explanation of what you want, it's hard to make any suggestions.
I have a table of users (and their info). I want to have a link so they could edit any given user. I realized that I couldn't use asp:button and asp:hyperlink controls because those controls won't show in the html table. I've tried
Edit
But it won't fire anything in the function below
protected void editBtn_ServerClick(object sender, EventArgs e)
{
//stuff
}
I've tried creating a click event when my page loads (as suggested in another question on stackoverflow) but this too doesn't work...
HtmlAnchor HA = new HtmlAnchor();
HA.ServerClick += new EventHandler(editBtn_ServerClick);
I don't want to send the user to another page but I can't use asp:button to accomplish what I want so thus am using .
Any help would be greatly appreciated! Thank you in advance.
Actually, you can most certainly pop up a dialog or some such to edit a given row.
And you can with ease drop in a plane jane button into that table, or in this case I suggest using a gridview, or even a listview (my favaorte).
so, lets do two simple things:
drop in a control to display our "table" or data. Then drop in a div to edit the data. That "div" will be what we pop up to edit that one row of "details" in a form like display (as opposed as you note trying to edit data "in place" in a row of data which is a poor UI).
So, say we have this markup for hte table (a grid view).
<asp:GridView ID="GridView1"
runat="server" CssClass="table" AutoGenerateColumns="false"
width="45%" DataKeyNames="ID" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
<asp:BoundField DataField="Description" HeaderText="Description" ItemStyle-Width="270" />
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit"
CssClass="btn" OnClick="cmdEdit_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Note how in above we just dropped in a plain jane asp.net button to "edit" the data.
While you can just drag + drop in the button from the toolbox, you can't double click on the button to create a click event, but you CAN in markup type in the onclick=
The instant you write "onclick=", (and hit the = button), then you get this in inteli-sense:
So, choose create event. After you do that, your button will show a plain jane click event, like this:
<asp:Button ID="cmdEdit" runat="server" Text="Edit"
CssClass="btn" OnClick="cmdEdit_Click" />
Might not seem like somthing occured, but we now have a simple click event wrired up and code behind will have such a code stub.
We go back to the above click event in a bit.
Ok, so now we need some code to load up the "table" (gridview).
That code is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
string strSQL = "SELECT * FROM tblHotelsA ORDER BY HotelName";
DataTable rstData = MyRst(strSQL);
GridView1.DataSource = rstData;
GridView1.DataBind();
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
And now we see/have this:
Ok, next part:
We need to create a "edit" area on this page. A simple "div" with some text boxes etc. will suffice.
We ALSO need somthing to pop up the "edit area". There are oh so many choices, and since 99% of web sites already have jQuery, then addopting and adding jQuery.UI to our project is a good choice. You don't want to "roll your own" dialog or popup system when so many "great" choices exist.
So, we will assume jQuery, and jQuery.UI for this simple popup.
The next part is some markup in a div for editing the row. It can be anything quite much you cook up, but say for each hotel, I have all the details I want to edit. Place your markup in our div.
So, lets call the div "editrecord".
So, this:
<div id="EditRecord" runat="server" style="float: left; display: none; border: solid 2px; padding: 15px">
<style>
.iForm label {display: inline-block;width: 90px
}
.iForm input {border-radius: 8px;border-width: 1px;margin-bottom: 10px
}
.iForm textarea {border-radius: 8px;border-width: 1px;margin-bottom: 10px
}
.iForm input[type=checkbox] {
margin-right: 8px
}
</style>
<div style="float: left" class="iForm">
<label>HotelName</label>
<asp:TextBox ID="txtHotel" runat="server" Width="280" />
<br />
<label>First Name</label>
<asp:TextBox ID="tFN" runat="server" Width="140" />
<br />
<label>Last Name</label>
<asp:TextBox ID="tLN" runat="server" Width="140" />
<br />
<label>City</label>
<asp:TextBox ID="tCity" runat="server" Width="140" />
<br />
<label>Province</label>
<asp:TextBox ID="tProvince" runat="server" Width="75"></asp:TextBox>
<br />
</div>
<div style="float: left; margin-left: 20px" class="iForm">
<label>Description</label>
<br />
<asp:TextBox ID="txtNotes" runat="server" Width="400" TextMode="MultiLine"
Height="150px" f="Description"></asp:TextBox>
<br />
<asp:CheckBox ID="chkActive" Text=" Active" runat="server" TextAlign="Right" />
<asp:CheckBox ID="chkBalcony" Text=" Has Balcony" runat="server" TextAlign="Right" />
</div>
<div style="clear: both"></div>
<asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn" />
<asp:Button ID="cmdCancel" runat="server" Text="Cancel" CssClass="btn" Style="margin-left: 10px" />
<asp:Button ID="cmdDelete" runat="server" Text="Delete" CssClass="btn" Style="margin-left: 20px" />
</div>
For now, lets just hide table, show edit div.
So,, our edit code becomes this:
protected void cmdEdit_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
GridViewRow gRow = btn.NamingContainer as GridViewRow;
int PKID = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
string strSQL = "SELECT * FROM tblHotelsA WHERE ID = " + PKID;
DataRow rstData = MyRst(strSQL).Rows[0];
txtHotel.Text = rstData["HotelName"].ToString();
tFN.Text = rstData["FirstName"].ToString();
tLN.Text = rstData["LastName"].ToString();
tCity.Text = rstData["City"].ToString();
tProvince.Text = rstData["Province"].ToString();
chkActive.Checked = (bool)rstData["Active"];
chkBalcony.Checked = (bool)rstData["Balcony"];
txtNotes.Text = rstData["Description"].ToString();
// hide table
GridView1.Style.Add("display", "none");
EditRecord.Style.Add("display", "nomral");
}
So, now we can click on any row, and the gv hides, and our edit area shows.
So, like this:
so, we can of course wire up the buttons to save.
but, the basic above approach quite much gets us our edit system, and one row click to launch edit for one row.
And assuming we have jQuery.UI installed?
Then we can change our edit button to not hide the table, but pop the above gv, and that code would look like:
So, we add this code to the client side:
<style>
.dialogWithDropShadow {
box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.5);
}
</style>
<script>
function pophotel() {
var mydiv = $("#EditRecord")
mydiv.dialog({
modal: true, appendTo: "form",
title: "Edit Hotel", closeText: "",
width: "835px",
dialogClass: "dialogWithDropShadow"
});
}
function MyClose() {
popdiv = $('#EditRecord')
popdiv.dialog('close')
}
</script>
and our server side (to fill out the div) is now this:
protected void cmdEdit_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
GridViewRow gRow = btn.NamingContainer as GridViewRow;
int PKID = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
string strSQL = "SELECT * FROM tblHotelsA WHERE ID = " + PKID;
DataRow rstData = MyRst(strSQL).Rows[0];
txtHotel.Text = rstData["HotelName"].ToString();
tFN.Text = rstData["FirstName"].ToString();
tLN.Text = rstData["LastName"].ToString();
tCity.Text = rstData["City"].ToString();
tProvince.Text = rstData["Province"].ToString();
chkActive.Checked = (bool)rstData["Active"];
chkBalcony.Checked = (bool)rstData["Balcony"];
txtNotes.Text = rstData["Description"].ToString();
// pop the edit div using jQuery.UI dialog
Page.ClientScript.RegisterStartupScript(Page.GetType(), "MyJava", "pophotel()", true);
}
So, we now get/see this:
So, note some imporant things:
First up, we don't have to show, expose, or even in the markup hide the database PK "id". The datakeys feature allows us to NOT expose this information to the client side.
And on row click, then we get the index of the clicked row, and then grab the database row, and hten load our "div", and then pop that div.
Note how nice the jQuery.UI dialog is. It gray out the background, and that is a "modal" popup.
As noted, even if you don't adopt jQuery.UI, you can hide the grid, show the edit div, and on save button, save the data, hide the div, and show the gridview. So, the extra "bonus" part 2 with a cool popup is really optional, and does not change much how the code works.
Of course, I should post the "save" button code, and I will if you ask or wish to see how the save button code works.
Edit: How to save the data back
So, in our load data, we save the PK, say like this:
Session["PKID"] = PKID;
and thus save code becomes this:
protected void cmdSave_Click(object sender, EventArgs e)
{
int PKID = (int)Session["PKID"];
string strSQL = "SELECT * FROM tblHotelsA WHERE ID = " + PKID;
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daU = new SqlCommandBuilder(da);
DataTable rstData = new DataTable();
rstData.Load(cmdSQL.ExecuteReader());
DataRow OneRow = rstData.Rows[0];
OneRow["HotelName"] = txtHotel.Text;
OneRow["FirstName"] = tFN.Text;
OneRow["LastName"] = tLN.Text;
OneRow["City"] = tCity.Text;
OneRow["Province"] = tProvince.Text;
OneRow["Active"] = chkActive.Checked;
OneRow["Balcony"] = chkBalcony.Checked;
OneRow["Description"] = txtNotes.Text;
da.Update(rstData);
}
// optional show update in gv
LoadGrid();
}
}
You will notice that we don't have to close the pop dialog, since a post-back will blow it out for us. (popup's can't survive a post-back).
You can see a example of mine based on the above.
Try this editing example to see such code in action:
Pop edit example
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am making a Canteen Management System using ASP.NET Forms.
So I want a Pop-Up window or box which will take input from dropdown list and textbox to implement Filter option.
So how to make it and how to access collected data from code behind?
Any tutorials links or suggestion are all welcome. Thanks for helping :)
There are quite a few ways to do this. If you using the AjaxControlToolKit, they have a fantastic pop up extender, and it takes no JavaScript.
However, probably the best choice is to use jQuery.UI. It is without a doubt your site and application has jQuery, so, I would add jQuery.UI. You can use nueget to install it, or simply go to the jquery site and download the jQuery.UI files. They are common.
So, the way we do this is you create (usually) a "div" on the page that is a popup. This works great since is responds to a "click" very fast (you don't even have to hit the server for the dialog to pop-up. However, the form you pop up might be to edit data.
The next consideration is that popup form cannot have post-backs. (well, ok, it can have one). So if the form you popup is to have some rich verification code, or code that requires some server side event code to run? You tend to be out of luck. So, you can easy pop a form, the user can edit (or enter data), but then you only allowed ONE post-back button event (say "ok - save"). So in most cases such a popup form is fine, but do keep in mind this limitation. If you do need some things to respond in that dialog, then you in most cases have to write ajax calls - that is extra pain and workload for the developer.
So, lets assume we want to pop up a dialog to filter a grid. The popup will allow the user to type in the first few characters of the hotel name OR WE can select a city from a drop down list to filter the grid by city.
and we toss in a show only "active" records with a check box.
So, how would this work, and look? (and keeping the above considerations in mind (only one post-back allowed in the pop dialog).
Well, we first build the grid. But, we need to add some buttons to the heading. So I have to drop a few of the databound fields, and use a template for that one column. This lets us setup the header with a button, or whatever we feel like.
And I did the same for the city heading.
So, we have this markup:
<div id="HotelGrid" runat="server" style="width:50%">
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table table-hover"
style="vertical-align:middle" ShowHeaderWhenEmpty="true">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:TemplateField>
<HeaderTemplate>
<asp:LinkButton ID="btnSearchCity"
runat="server"
CssClass="btn-default btn-sm"
>City
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblCity" runat="server" Text='<%# Eval("City") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:TemplateField HeaderStyle-Width="200px">
<HeaderTemplate>
<asp:LinkButton ID="cmdSearchHotel"
runat="server"
CssClass="btn-default btn-sm"
OnClientClick="return mysearch(this);"
OnClick="cmdSearchHotel_Click"
>Hotel
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server" Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Description"HeaderText="Description" />
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center" >
<ItemTemplate>
<asp:CheckBox ID="chkActive" runat="server" Checked='<%# Eval("Active") %>' />
</ItemTemplate>
<ItemStyle HorizontalAlign="Center"></ItemStyle</asp:TemplateField>
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit"class="btn" OnClick="cmdEdit_Click"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now, you can see in above, the markup starts to grow - that's due to gridview requiring "template" around each set of controls. (I often suggest using a listview, since you don't need the template(s). But no big deal.
Ok, so we have the above markup.
My page load code to load the grid? Well, we want the heading to dispaly, so we do it this way:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
GHotels.DataSource = MyRst("select * from tblHotels where id = 0")
GHotels.DataBind()
' load the city combo box
cboCity.DataSource = MyRst("SELECT City from tblCity ORDER BY City")
cboCity.DataBind()
cboCity.Items.Insert(0, "") ' allow blank selection
End If
End Sub
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using MyCon As SqlConnection = New SqlConnection(My.Settings.TEST3)
Using cmdSQL As New SqlCommand(strSQL, MyCon)
cmdSQL.Connection.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
Ok, so we now see/have this:
Now, the two buttions in the grid heading will have TWO parts.
The part to pop the dialog (jQuery.UI), and then the standard code server side.
Ok so, we have to create a div to hold our pop up.
It will be rather simple, and just combo box (for city), a text box for hotel anme, and a check box for "active only" filter.
so, that div is quite simple. and note when we happy with the div layout, we add display:none to hide the div.
so we have this:
<div id="mysearchdiv" style="border:solid;width:300px;text-align:right;padding:15px;font-size:large;display:NONE">
<p>Select City
<asp:DropDownList ID="cboCity" runat="server" width="150px"
DataTextField="City"
DataValueField="City"
></asp:DropDownList>
</p>
<p>
Hotel Name
<asp:TextBox ID="txtSearchHotel" runat="server" Width="150" Height="25"></asp:TextBox>
</p>
<p>
Include Only Active
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</p>
<asp:HiddenField ID="cmdOption" runat="server" ClientIDMode="Static"/>
</div>
Really very simple markup.
Ok, now the hard part, the jQuery UI is a java script routine, and it is this:
<script>
var searchok = false
function mysearch(btn) {
if (searchok) {
return true
}
var myDialog = $("#mysearchdiv");
myDialog.dialog({
title:"Search For Hotels",
modal: true,
width: "320px",
resizable: false,
appendTo: "form",
autoOpen: true,
buttons: {
Ok: function ()
{
searchok = true
btn.click()
},
Clear: function () {
searchok = true
$('#cmdOption').val('c')
btn.click()
},
Cancel: function () {
myDialog.dialog('close')
}
}
});
return false
}
</script>
So, it is a bit of code, but what jQuery.UI is "grabs" that div, and converts it into a nice dialog. So the end result is this:
Now, either the c# tag was added after I started typing this, or I missed it.
but, the c# code is much the same. The first page load code is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GHotels.DataSource = MyRst("select * from tblHotels where id = 0");
GHotels.DataBind();
// load our search combo box
cboCity.DataSource = MyRst("SELECT City from tblCity ORDER BY City");
cboCity.DataBind();
cboCity.Items.Insert(0,new ListItem("",""));
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlCommand cmdSQL = new SqlCommand(strSQL,
new SqlConnection(Properties.Settings.Default.TEST3)))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
return rstData;
}
So above will load up the grid (we send it a blank row, since we using the header for searching.
and the buttion click? Well, we pop a jquery dialog. And if it returns true, or false - that determines if the server side buttion will fire.
So, we have this:
<asp:TemplateField HeaderStyle-Width="200px">
<HeaderTemplate>
<asp:LinkButton ID="cmdSearchHotel"
runat="server"
CssClass="btn-default btn-sm"
OnClientClick="return mysearch(this);"
OnClick="cmdSearchHotel_Click"
>Hotel
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server" Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Note very carefull how we have the jQuery search routine return true ,or false.
Ok, so now it is a simple matter to write that code to filter/search the grid based on that popup.
The code is quite simple, and we "cumulative" add up each search option, or simple skip the options if no value in the search box is entered.
And, we added that hidden field, since as you can see, we can now add more buttons to that dialog, but not have to create new code server side - but just use the one button click to handle all options for that dialog.
And the c# code for this filtering is thus:
protected void cmdSearchHotel_Click(object sender, EventArgs e)
{
if (cmdOption.Value == "c")
{
// clear the search option
cboCity.Text = "";
txtSearchHotel.Text = "";
chkActiveOnly.Checked = false;
cmdOption.Value = "";
GHotels.DataSource = MyRst("select * from tblHotels where id = 0");
GHotels.DataBind();
return;
}
// filter the grid
string strWhere = "";
using (SqlConnection con = new SqlConnection(Properties.Settings.Default.TEST3))
using (SqlCommand cmdSQL = new SqlCommand("SELECT * FROM tblHotels",con))
{
if (cboCity.Text != "")
{
strWhere += "City = #City";
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = cboCity.Text;
}
if (txtSearchHotel.Text != "")
{
if (strWhere != "")
strWhere += " AND ";
strWhere += "HotelName like #Hotel + '%'";
cmdSQL.Parameters.Add("#Hotel", SqlDbType.NVarChar).Value = txtSearchHotel.Text;
}
if (chkActiveOnly.Checked)
{
if (strWhere != "")
strWhere += " AND ";
strWhere += "Active = 1";
}
if (strWhere != "")
cmdSQL.CommandText += " WHERE " + strWhere;
cmdSQL.CommandText += " ORDER BY HotelName";
con.Open();
GHotels.DataSource = cmdSQL.ExecuteReader();
GHotels.DataBind();
}
So, all in all:
A absoulte min of code.
Not really much more markup then a typical grid.
And I shared a LONG time super cool trick that VERY VERY VERY few have used. That is how to get the one jQuery.UI dialog to NOT fire the server side button if we don't want to. And thus we don't need multiple routines in java, and we don't need multiple routines server side. We simply have the one button call the dialog, and it returns true, or false. But it STILL is running asyncrious as all and most JavaScript widgets should be. (no blocking code allowed!!!).
You can create fied position DIV and show it using JS,JQuery, ... whenever you want to show the dialog.
then you can read input data.
How to generate a simple popup using jQuery
I have a datalist which is populated with values from a database. When the user clicks a checkbox, I want to loop through all of the datalist items and hide all of the items that have the property isActive = false (which is displayed as "Disabled" in a text label). The item template consists of a table that contains multiple other items, buttons etc, which have not been included below. I therefore want to hide all elements that are found under the itemtemplate of a specific item.
My idea was to just hide the entire table by accessing its id, and then setting the table's visible property to false. This is currently not doing anything when I run the code. Any help will
appreciated!
<asp:CheckBox runat="server" Text="Filter by active postings" OnCheckedChanged="filterByActive"/>
<asp:DataList ID="postingsDataList" runat="server" OnItemCommand="itemCommand" >
<ItemTemplate>
<div class="postingRow">
<table class="postingTable" id="posting">
<tr>
<td>
<asp:Label ID="lblActive" runat="server" Text=<%#Eval("isActive").ToString().Equals("True") ? "Active ✅" : "Disabled ❌"%>/>
</td>
</tr>
</table>
</div>
</ItemTemplate>
</asp:DataList>
Code Behind:
protected void filterByActive (object sender, EventArgs e)
{
int count = postingsDataList.Items.Count;
CheckBox check = (CheckBox)sender;
if (check.Checked == true)
{
for (int i = 0; i < count; i++)
{
Label lblActive = postingsDataList.Items[i].FindControl("lblActive") as Label;
string isActive = lblActive.Text.ToString();
if (isActive.Equals("Disabled ❌"))
{
Table tbl = postingsDataList.Items[i].FindControl("posting") as Table;
tbl.Visible = false;
}
}
}
else
{
for (int i = 0; i < count; i++)
{
Label lblActive = postingsDataList.Items[i].FindControl("lblActive") as Label;
string isActive = lblActive.Text.ToString();
if (isActive.Equals("Active ✅"))
{
Table tbl = postingsDataList.Items[i].FindControl("posting") as Table;
tbl.Visible = true;
}
}
}
}
}
Ok, I suggest you do this:
Persist your table - thus you don't have to hit sql server again. (but, you could - not the end of the world).
I don't have your data, but I have a simple list of hotels - and there is a Active column for the Hotel. So, lets filter the data based on checking the check box, not have to hit the database server again. And EVEN BETTER is if we un-check the box, we can display all records we had.
We assume of course this is not a lot of data.
Ok, so we have this for our markup:
(really does not matter a whole lot)
<asp:DataList ID="DataList1" runat="server" DataKeyField="ID" RepeatColumns="4" RepeatDirection="Horizontal" >
<ItemTemplate>
<div style="border-style:solid;color:black;width:300px;">
<div style="padding:5px;text-align:right">
<p>Hotel Name: <asp:TextBox ID="HotelName" runat="server" Text ='<%# Eval("HotelName") %>' /></p>
<p>First Name: <asp:TextBox ID="FirstName" runat="server" Text ='<%# Eval("FirstName") %>' /></p>
<p>Last Name: <asp:TextBox ID="LastName" runat="server" Text ='<%# Eval("LastName") %>' /></p>
<p>City: <asp:TextBox ID="City" runat="server" Text ='<%# Eval("City") %>' /></p>
<p>Province: <asp:TextBox ID="Province" runat="server" Text ='<%# Eval("Province") %>' /></p>
Active: <asp:CheckBox ID="Active" runat="server" Checked = '<%# Eval("Active") %>'/>
</div>
</div>
</ItemTemplate>
</asp:DataList>
Now, our code to load could be this:
DataTable rstData = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadData();
ViewState["MyData"] = rstData;
}
else
rstData = (DataTable)ViewState["MyData"];
}
void LoadData()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL = "SELECT top 10 * from tblHotels ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
DataList1.DataSource = rstData;
DataList1.DataBind();
}
}
}
And now we have this:
Now, our filter show/hide becomes JUST this:
protected void ckFilter_CheckedChanged(object sender, EventArgs e)
{
// filter based on check box
if (ckFilter.Checked)
rstData.DefaultView.RowFilter = "Active = 1";
else
rstData.DefaultView.RowFilter = "";
DataList1.DataSource = rstData;
DataList1.DataBind();
}
And BETTER is if I un-check the check box, all the data is re-displayed. And we don't have to re-hit the database to do this!!!
Now, we COULD also just hide/show each row, and then un-hide if for some reason you don't want to persist the data table as I did per above.
Checking on the box filters to this:
As noted, if I un-check the box, then I get all the data back - all without hitting the database again.
Edit:=========================================
Note that if you NOT using the above horizontal across, but just rows down?
Then you can just as well format to hide/show the rows, and you do NOT have to persist the data table.
You can apply formatting say by doing this:
protected void ckFilter_CheckedChanged(object sender, EventArgs e)
{
foreach (DataListItem gRow in DataList1.Items)
{
// get checkbox
CheckBox ckActive = (CheckBox)gRow.FindControl("Active");
// get div
HtmlGenericControl Myiv = (HtmlGenericControl)gRow.FindControl("myrow");
string MyFormat = "normal";
if (ckFilter2.Checked)
{
// only show active ones
if (ckActive.Checked)
MyFormat = "normal";
else
MyFormat = "none";
}
Myiv.Style["display"] = MyFormat;
}
}
So the above does work fine. BUT the restriction is that you can't have a set of horizontal across data items like my original screen shot
(it actually still works but in fact hide each panel with a blank space).
So, if your as noted using vertical layout (and it looks to be that you are).
Note for above, I added a simple ID to the "div", and runat server like this:
<ItemTemplate>
<div id="myrow" runat="server"
style="border-style:solid;color:black;width:300px;">
Then skip my first example. You can loop the data list rows, and hide, or un-hide. And even more amazing is that if you un-hide - then the rows all do re-appear and persist correct.
I had pulled a working example - but I was trying to figure out why I had to persist the data - the reason was the "horizontail" across settings.
But, as above shows, no real need to persist the data source table - you can process the data list rows, and hide/show each one conditionals, and you can do this without a data re-bind.