Sorting Listview - c#

I have A listview which I want to sort.
My problem is that when I click the sorting column the Onsorting event only fires when I Bind the data on pageload again.
This means that on every pageload I will first have to bind the data, then I can catch the OnBinding event and after that I can Rebind the data again.
Is there a better way to do this. Basically what I want is to bind the data only in the onsorting event
<asp:ListView ID="TempList" runat="server" OnSorting="TempList_sorting">
<LayoutTemplate>
<table >
<tr>
<th >
<asp:LinkButton runat="server" ID="btnSortVoorletters2" CommandName="Sort" Text="Voorletters"
CommandArgument="Voorletters" OnClick="btnSortVoorletters_Click" />
</th>
</tr>
<tr runat="server" id="itemPlaceholder">
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="EmpIDLabel" runat="server" Text='<%# Eval("Naam") %>'/>
</td>
</tr>
</ItemTemplate>
<EmptyDataTemplate>
<p>Empty text that will be displayed.</p>
</EmptyDataTemplate>

It lloks that you're always binding in PageLoad so that the previously supplied order is lost. Bind only if IsPostback is false. (You need to have the ListView EnableViewState set to true, which is the default value).
if(!IsPostback)
{
// do the binding
}
When the user clicks the 'Sort' button, the event will be fired and your event will sort and bind the data accordingly.
If the page is reloaded, and you don't rebind it in PageLoad this will be enough.
However, if for some reason you really need to rebind in PageLoad, what you have to do is to store the sorting in ViewState, a HiddenField or Session so that you can get the value from there to sort the data before binding it in PageLoad.
You should take the code that sorts and binds to a new method, and call it from both the Sort and the PageLoad events.

Related

DropDownList value is blank when saving a FormView's filtered result

I have a FormView that is used for viewing, editing and inserting items into a MSSQL database. The FormView is wired up to a LinqDataSource, and I use its Selecting event to filter the data displayed in the FormView based on parameters (columns) passed in the query string.
In the FormView I have a DropDownList that displays values from a related table. Everything works as it should except when I try to edit - for some reason, the selected value of the DropDownList is always empty when I try to save the edit (even when I have a value selected). The insert works as it should.
I have traced the problem down to my Selecting event where I do the filtering. If I comment out the method that does the filtering, it updates the item successfully - but I can't figure out why the filtering is breaking the update.
Here is my (shortened) FormView:
<asp:FormView ID="fvData" runat="server" AllowPaging="True"
DataKeyNames="ID" DataSourceID="ldsData"
ondatabound="fvData_DataBound">
<EditItemTemplate>
<table class="pad5">
<tr>
<td class="field-name">AREA:</td>
<td><asp:DropDownList ID="cboAREA" runat="server" DataTextField="AREA_NAME" DataValueField="AREA1" SelectedValue='<%# Bind("AREA") %>' DataSourceID="ldsAreas" /></td>
</tr>
<tr>
<td class="field-name">LOOP:</td>
<td><asp:TextBox ID="txtLOOP" runat="server" Text='<%# Bind("LOOP") %>' /></td>
</tr>
<tr>
<td class="field-name">LOOP DESCRIPTION:</td>
<td><asp:TextBox ID="txtLOOP_DESCRIPTION" runat="server"
Text='<%# Bind("LOOP_DESCRIPTION") %>' style="width: 600px" /></td>
</tr>
</table>
<asp:Button ID="btnUpdate" runat="server" Text="Update" CommandName="Update" CausesValidation="True" />
<asp:Button ID="btnCancel" runat="server" Text="Cancel" CommandName="Cancel" CausesValidation="False" />
</EditItemTemplate>
<InsertItemTemplate>
<table class="pad5">
<tr>
<td class="field-name">AREA:</td>
<td>
<asp:DropDownList ID="cboAREA" runat="server" DataTextField="AREA_NAME"
DataValueField="AREA1" SelectedValue='<%# Bind("AREA") %>' AppendDataBoundItems="true" DataSourceID="ldsAreas">
<asp:ListItem Text="" Value="" />
</asp:DropDownList>
</td>
</tr>
<tr>
<td class="field-name">LOOP:</td>
<td><asp:TextBox ID="txtLOOP" runat="server" Text='<%# Bind("LOOP") %>' /></td>
</tr>
<tr>
<td class="field-name">LOOP DESCRIPTION:</td>
<td><asp:TextBox ID="txtLOOP_DESCRIPTION" runat="server"
Text='<%# Bind("LOOP_DESCRIPTION") %>' style="width: 600px" /></td>
</tr>
</table>
<asp:Button ID="btnInsert" runat="server" Text="Insert" CommandName="Insert" CausesValidation="True" />
<asp:Button ID="btnCancel" runat="server" Text="Cancel" CommandName="Cancel" CausesValidation="False" />
</InsertItemTemplate>
</asp:FormView>
The LinqDataSource:
<asp:LinqDataSource ID="ldsData" runat="server"
ContextTypeName="E_and_I.EAndIDataDataContext" EnableDelete="True"
EnableInsert="True" EnableUpdate="True" EntityTypeName=""
TableName="INSTRUMENT_LOOP_DESCRIPTIONs" onselecting="ldsData_Selecting" OrderBy="ID ASC" >
</asp:LinqDataSource>
My ldsData_Selecting method:
protected void ldsData_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
EI.FilterData<INSTRUMENT_LOOP_DESCRIPTION>(ref e, db.INSTRUMENT_LOOP_DESCRIPTIONs, this.db);
}
And finally EI.FilterData:
public static void FilterData<T>(ref LinqDataSourceSelectEventArgs e, IEnumerable<T> source, EAndIDataDataContext db)
{
if (HttpContext.Current.Request.QueryString.Keys.Count > 0)
{
var result = source.AsQueryable();
bool filtered = false;
// get column names
var columnNames = db.Mapping.MappingSource.GetModel(typeof(EAndIDataDataContext)).GetMetaType(typeof(T)).DataMembers;
foreach (string key in HttpContext.Current.Request.QueryString.Keys)
{
string val = HttpContext.Current.Request.QueryString[key];
// check the query string key exists as a column in the table, etc
if (columnNames.SingleOrDefault(c => c.Name == key) != null && val.Trim() != "" && val != "*")
{
result = result.WhereLike(key, val.Replace("?", "_").Replace("*", "%"));
filtered = true;
}
}
if (filtered)
e.Result = result;
}
}
Is there any reason filtering the results would break the update (and ONLY the DropDownList's - textboxes work fine)? The filtering works perfectly (that is, the FormView only shows the records based parameters entered by the user); if you're wondering what the WhereLike extension method does, you can check out this question's answer.
Because when you post data with editing, you re bind your data and so you erase the selected Value.
Solution : Adjust your bind
If( ! IsPostBack)
{
//Here realize your bind of data
}
In order to persist your datas, use ViewState
With this solution When you post you don't re bind data, and so ViewState contains your selected value
There's a difference in the drop-down lists for your two cases, which I think is probably the cause of this. For Insert, you have AppendDataBoundItems="true", while for the Update form above it, this flag is not set (and it defaults to false). What that means in terms of the submitting form is that, for the Insert form, when it's rebinding it appends the items to the current list instead of clearing them; but for the Update form, because it's not set to append, it will clear the items and THEN binds them -- so the Binding is happening in both cases, but in the case of the Update form, it's clearing the items when that happens and giving you blank data.
Instead of just rejecting the filtering on Postback, which causes your form to fail eventually, I would instead filter based on the control that CAUSED the Postback. At the top of the function you can capture the control ID that caused the postback, and then you can filter only when it isn't a postback coming from the buttons that are triggering the data storage step. If that's in place, I believe you should be able to do away with the AppendDataBoundItems flags altogether.
A code snippet update of what I mean:
string initControl = Request.Form["__EVENTTARGET"];
if (!IsPostBack || (initControl != "btnInsert" && initControl != "btnUpdate") {
// code here
}
What this does is expand the check for PostBack so that the conditions are allowed EITHER if not a post back (which you tested previously), but critically, it'll also allow the lists to update if the form IS posted back, so long as the control posting back isn't one that is triggering an event dependent on the contents of those bound elements. That should mean that you avoid the problem of it only working for the first page load.
Additionally, if you need the control to bind regardless, you could add a global boolean variable to the script; set it to False by default, and then set it to True if the above condition is not met (i.e., if you're preventing the binding). Then you can check that boolean value in the Page_PreRender function, and if it's set to true, you can perform a late binding of the control at that step (which will only fire after the Insert/Update events have already processed, so any binding at that point will no longer affect the result of the form processing).

ASP.NET ListView control not firing OnItemCommand Event

I know that this sounds like a number of other posts, all of which I have read but have not addressed my issue.
Here's the Scenario ...
I have BOTH a Repeater and a ListView bound to the same Data Source. Each control contains an ASP:LinkButton which, when clicked, should fire the OnItemCommand event. Although they are wired to the EXACT same data at the EXACT same places in the page life cycle and View State is enabled for the page and each individual control the Repeater appears to fire the event and the ListView does not.
I know that the event will not fire if the data is not bound BEFORE the assignment of the event handler. I am relying on ViewState to repopulate the controls when the page is posted back to. Looking at each control in debug mode while stepping through a request I can see that the Repeater DOES indeed appear to repopulated with the ViewState data but the ListView does not.
As these are both generated, populated, bound, and handled almost IDENTICALLY I am at a complete loss why this may be happening. I have also noticed a similar issue with the GridView control (it does NOT fire the event). I assume that these are related somehow.
The only thing that I can think of that the GridView and ListView have in common that the Repeater does not is the built-in paging capability. Whether implemented or not is there something with the paging that affects the loading of the ViewState?
OrderControl.ASCX is a control which exposes the ListView and Repeater as properties (OrderListLV & OrderListRPT) to the host page/application.
<asp:ListView runat="server" id="lvOrderList" OnItemDataBound="lstOrderList_OnItemDataBound" EnableViewState="true" >
<LayoutTemplate>
<table class="tblGrid">
<tr runat="server" id="itemPlaceholder" />
</table>
<ASP:DataPager runat="server" ID="dataPager1" PageSize="3">
<Fields>
<ASP:NextPreviousPagerField
ButtonType="Button"
ShowFirstPageButton="true"
ShowLastPageButton="true"
ShowNextPageButton="true"
ShowPreviousPageButton="true" />
</Fields>
</ASP:DataPager>
</LayoutTemplate>
<ItemTemplate>
<tr class="row-">
<td align="center"><ASP:LinkButton runat="server" id="lnkOrderId1" /></td>
</tr>
</ItemTemplate>
</asp:ListView>
<asp:Repeater runat="server" id="rptOrderList" OnItemDataBound="rptOrderList_ItemDataBound">
<HeaderTemplate>
<table class="tblGrid">
</HeaderTemplate>
<ItemTemplate>
<tr">
<td align="center"><ASP:LinkButton runat="server" id="lnkOrderId" /></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
OrderControl.ASCX.CS is where the controls are bound to the data source in the Pre-Render stage, well after ViewState has had the opportunity to reconstitute itself.
protected override void OnPreRender(EventArgs e)
{
this.lstOrderList.DataSource = this.OrderHeaders.OrderByDescending(x => x.OrderDate).ToList();
this.lstOrderList.DataBind();
this.rptOrderList.DataSource = this.OrderHeaders.OrderByDescending(x => x.OrderDate).ToList();
this.rptOrderList.DataBind();
}
Host.ASPX.CS is the page which consumes the control. It attaches the event handlers directly the controls in it's OnLoad handler.
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.OrderControl.OrderListRPT.ItemCommand += new RepeaterCommandEventHandler(OrderList2_ItemCommand);
this.OrderControl.OrderListLV.ItemCommand += new EventHandler<ListViewCommandEventArgs>(OrderList_ItemCommand);
}
After all is said and done when I click on the LinkButton in each control the ItemCommand Handler for the Repeater fires and executes correctly but the process doesn't even enter the handler for the ListView handler.
I am crazy confused on this issue. I am hoping that someone might have some thoughts on this. Something I can try at least?
Thanks,
Gary
you should set the CommandName property of each LinkButton in the ListView, eventually also the CommandArgument.
<td align="center">
<asp:LinkButton runat="server" id="lnkOrderId1" CommandName="yourCommandName" CommandArgument="yourCommandArgument" />
</td>
also check asked questions here in SO before posting a new question ;-)
listview OnItemCommand dosen't fire up

Need help with repeater

This is my repeater:
<asp:Repeater ID="myRepeater" OnItemCommand="myRepeater_ItemCommand" runat="server" OnItemDataBound="myRepeater_OnItemDataBound">
<HeaderTemplate>
<table width="99%" border="0" cellpadding="0" cellspacing="0">
<tr class="lgrey">
<td>Default</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<table>
<tr>
<td>
<asp:LinkButton ID="lnk1" Text="Make Default" CommandName="SetDefault" runat="server" Visible="True" CommandArgument='<%#Eval("UserID") %>' CausesValidation="false"></asp:LinkButton>
<asp:Label ID="label1" Text="Yes" runat="server" Visible="False"></asp:Label>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
What I want is that when user clicks on any of
the "lnk1" link button in the list that repeater renders,
the link should be replaced with the label "label1"..
i.e. when the user clicks on "Make Default" link, it should be replaced with "Yes" label
Calling this method obj.SetDefaultAddress(); is setting the default address in the DB alright..
problem is with the display of the label1 and lnk1 when the repeater renders...
what is happening is that BOTH "Make Default" LinkButton and the "YES" label are getting displayed
under the "Default" column of the table inside my repeater.
I want some code that will check the "IsDefault" value in my DB and display "Make Default " link button
and "YES" label accordingly... i.e. if IsDefault's value in the DB is TRUE then "YES" should be displayed in the repeater
otherwise "Make Default"
Are you sure your piece of code in code behind under ItemCommand is executing?
I only changed the CommandName from SetDefault to SetDefaultAddress in aspx file to match with the one in code behind, it worked.
Where to start...
I think what's causing your problem is that the SelectedItem and the DefaultAddress are not mapped to each other, so when you click the button you're getting the selected index set and the OnItemDatabound event is showing/hiding what you want, but when the grid is initialized from the database, the SelectedItem is not being set.
I don't know what your datasource is, and there's obviously more code to this than what you've posted, but if you can look at the e.Item.DataItem in the myRepeater_ItemDataBound handler, you can set the current item as selected when the address is the default (e.Item.ItemType... or use your "selectedIndex" counter)
I will probably do it from markup itself - this is assuming that you have "IsDefault" column/property of bit/boolean type in your data-source indicating the address is default. So use following markup:
...
<tr>
<td>
<asp:LinkButton ID="lnk1" Text="Make Default" CommandName="SetDefault" runat="server" Visible='<%# !Eval("IsDefault") %>' CommandArgument='<%#Eval("UserID") %>' CausesValidation="false"></asp:LinkButton>
<asp:Label ID="label1" Text="Yes" runat="server" Visible='<%# !Eval("IsDefault") %>'></asp:Label>
</td>
</tr>
...
You need to control visibility based on property in your data source (either using markup or ItemDataBound event). Also when SetDefault link is clicked, you must either re-bind the repeater new state or toggle visibility explicitly (as your current code is doing).
EDIT:
If data binding expression are not working then you have to do it in ItemDataBound event. I see that you have already tried that but there is one mistake - bllUsers obj=new bllUsers(); will always have IsDefault as false - you need to use data item. For example,
protected void myRepeater_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
bllUsers obj = e.Item.DataItem as bllUsers;
((Label)e.Item.FindControl("ldefault")).Visible = obj.isDefault;
((Button)e.Item.FindControl("btnMakeDefault")).Visible = ! obj.isDefault;
}
}

How can I use the ScrollTo jQuery plugin to scroll to particular row in a repeater in ASP.NET?

I have a simple repeater that looks like:
<asp:Repeater runat="server" ID="rptOptions" OnItemDataBound="rptOptions_ItemDataBound">
<HeaderTemplate>
<thead>
<tr>
<td class="GridHeader">Account</td>
<td class="GridHeader">Margin</td>
<td class="GridHeader">Symbol</td>
<td class="GridHeader">Usymbol</td>
</tr>
</thead>
</HeaderTemplate>
<ItemTemplate>
<tbody>
<tr runat="server" ID="trOption">
<td class="GridRow"><asp:Label runat="server" ID="lblOptionAccount"></asp:Label></td>
<td class="GridRow"><asp:Label runat="server" ID="lblOptionMargin"></asp:Label></td>
<td class="GridRow"><asp:Label runat="server" ID="lblOptionSymbol"></asp:Label></td>
<td class="GridRow"><asp:Label runat="server" ID="lblOptionUsymbol"></asp:Label></td>
</tr>
</tbody>
</ItemTemplate>
</asp:Repeater>
Now, in my code-behind I have an event which is fired that is supposed to add/insert a row into the database. After this happens, I re-grab the new list of options from the database and re-bind them to the repeater. This takes place inside an update panel so the list refreshes right away for the user.
protected void lbtnAddOptionSave_Click(object sender, EventArgs e)
{
SelectedOption = new Option()
{
Account = txtAddOptionAccountNumber.Text,
Margin = chkAddOptionMargin.Checked,
Symbol = txtAddOptionSymbol.Text,
Usymbol = txtAddOptionUsymbol.Text,
};
Presenter.OnAddOption(); // Insert new option into database
RefreshOptions(); // Re-get list of options, bind them to repeater
}
Now, what I would ~love~ to do, is use the jQuery ScrollTo plugin to scroll straight to the newly added row.
What would be the best way to call the ScrollTo() method in the jQuery plugin so I scroll to that particular row that was just added? Is there anyway I can mark my rows in my ItemTemplate so I can easily select an element to scroll to via jQuery?
Ideally, right after RefreshOptions() I would like to execute the ScrollTo function to scroll down to the new row.
If you know the client side Id of the row (which you can get), its relatively painless to simply call
$(document).scrollTo("#<row-id-here>", 800);
When you add the object to the database (or just after that), grab the id of the newly inserted object. Modify the repeater to include a Label with Visible="false" so that it doesn't get rendered to the client. Hook into the ItemDataBound event and check each label against the id you've grabbed. When you find the matching row, you can get the id of the row and then you'll be able to use for the scrolling parameter.
Note: Other data-bound controls have a DataKey property which could be used for the id of the object and make this a bit simpler. Not sure if you're tied to the Repeater at this point, but a GridView or ListView could be worth looking into.

Custom edit/delete button Gridview

I am using C#.net
I want to add custom edit/delete buttons to my GridView1 (one edit/delete button per row).
However I want the buttons to access another view (editView/deleteView within the same form), rather than edit ‘inline’ etc.
The edit button seems to be working fine. Here’s how I created it manually:
Right clicked on GridView1
Clicked on ‘Add New Column’
Field Type: ButtonField
Header Text: Edit
Button Type: Button
Command Name: Edit
Text: Edit
Within the ‘Events’ section (located under properties) for GridView1, I double clicked on the RowEditing, this then created a Event I could access within the code behind.
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
// Access _viewAdd
_multiView1.ActiveViewIndex = 1;
}
The delete button should access the deleteView (confirmation page) rather than just automatically deleting a row. I want to create a custom method that is triggered when the user selects the delete button.
I ended up using a repeater and amending both a edit/delete button onto the end of each row. These button not only held the OnClick_Event information but also the ID associated with that row.
<asp:Repeater ID="Repeater" runat="server" DataSourceID="*****">
<HeaderTemplate>
<table cellpadding="3" cellspacing="3">
<tr>
<th style="text-align:left">Name</th>
<th> </th>
<th> </th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td style="text-align:left"><%#Eval("forename")%> <%#Eval("surname")%></td>
<td style="text-align:left"><asp:Button ID="edit" OnCommand="edit_Click" CommandArgument='<%#Eval("id")%>' runat="server" Text="Edit" CssClass="standardButton" /></td>
<td style="text-align:left"><asp:Button ID="delete" OnCommand="delete_Click" CommandArgument='<%#Eval("id")%>' runat="server" Text="Delete" CssClass="standardButton" /></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
I hope that helps other people.
There is a RowDeleting event you can handle as well. Both event args have a Cancel property you can set to true to prevent the data from being modified.

Categories