Sorting a ListBox of objects by attributes - c#

I have a list created by:
List<Song> SongList = new List<Song>();
Populated by a bunch of:
SongList.Add(new Song(songID, "Dirt", "Alice in Chains", "Rooster", "Rock", "02:32"));
The details of songs are populated into a ListBox by:
private void songTitle_TextChanged(object sender, EventArgs e)
{
i = 0;
for (; i < songTitle.Text.Length; i++)
{
songResultBox.Items.Clear();
var songResult = from song in SongList
where song.SongTitle != null && song.SongTitle.Length >= songTitle.Text.Length
&& songTitle.Text == song.SongTitle.Substring(0, i+1)
select new { sId = song.SongID, album = song.SongAlbum, artist = song.SongArtist, title = song.SongTitle,
genre = song.SongGenre, length = song.SongLength };
foreach (var item in songResult)
{
songResultBox.Items.Add(new Song(item.sId, item.album, item.artist, item.title, item.genre, item.length));
songResultBox.DisplayMember = "FullName";
songResultBox.ValueMember = "songID";
}
}
}
Question is: How would I create a button (or 4 in fact) that took the contents of the ListBox 'songResultBox' and sorted its contents by title, album, artist, genre etc.

Create the button, label it depending on what property you want to sort on, add a click event to the button, sort the items (hopefully you've maintained a list of them), then repopulate the listbox:
private bool descendingSongTitleSort = false;
private bool descendingArtistSort = false;
// Artist button clicked event
private void artistButtonClicked(object sender, EventArgs args)
{
Func<Song, IComparable> sortProp = (song => song.Artist);
sortListBox(songResultBox, descendingArtistSort, sortProp);
descendingSongTitleSort = false;
descendingArtistSort = !descendingArtistSort;
}
// Title button clicked event
private void titleButtonClicked(object sender, EventArgs args)
{
Func<Song, IComparable> sortProp = (song => song.Title);
sortListBox(songResultBox, descendingSongTitleSort, sortProp);
descendingSongTitleSort = !descendingSongTitleSort;
descendingArtistSort = false;
}
// Sorting function
private void sortListBox(
ListBox box,
bool descending,
Func<Song, IComparable> sortProperty)
{
List<Song> items = new List<Song>();
foreach (Object o in box.Items)
{
Song s = o as Song;
items.Add(s);
}
box.Items.Clear();
if(descending)
{
items = items.OrderByDescending(sortProperty).ToList();
}
else
{
items = items.OrderBy(sortProperty).ToList();
}
foreach(Song s in items)
{
box.Items.Add(s);
}
}
The descending bools aren't necessary if you don't want to worry about resorting in the opposite direction.

Related

How to search file and display it in list box?

I am stuck with the project C# and I don't know how to solve it. I have a text file "cars.txt" and it has this information:
1950
Nissan Sentra
Ford Focus
1951
Mazda5
Mazda3
Toyota
1952
Chevy
I have to have 2 list boxes and one button. The first list box supposed to search through the file and populate years and when user select year and click on the button and it displays the corresponding cars models for this specific year. I have thoughts about using StreamReader but I don't know how to start.
Your help appreciated
Create a dictionary of string lists that will contain car lists with the year a key as well as a list for the years:
private readonly Dictionary<int, List<string>> _carsByYear =
new Dictionary<int, List<string>>();
private readonly List<int> _years = new List<int>();
Then you can fill it with
List<string> cars = null;
foreach (string line in File.ReadLines(#"C:\Users\Me\cars.txt")) {
if (!String.IsNullOrWhiteSpace(line)) {
if (Int32.TryParse(line, out int year)) { // We have a year
if (_carsByYear.TryGetValue(year, out var existingList)) {
cars = existingList;
} else {
// Add a new list with year as the key
_years.Add(year);
cars = new List<string>();
_carsByYear.Add(year, cars);
}
} else { // We have a car
cars.Add(line);
}
}
}
Now you can assign _years to the DataSource of the first ListBox. You can get the selected year (SelectedIndexChanged event) with
int year = (int)listBox1.SelectedItem;
With this year, you can get the cars list with
var selectedCarList = _carsByYear[year];
Assign it to the DataSource of the second ListBox.
now the is no error but nothing displayed. This is a very challenging
assignment. everyone in my class is stuck.
Works fine for me. Here's a variation with some examples of how you could use it:
private readonly SortedList<int, SortedSet<string>> _carsByYear = new SortedList<int, SortedSet<string>>();
private void button1_Click(object sender, EventArgs e)
{
SortedSet<string> cars = null;
string fileName = System.IO.Path.Combine(
System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"cars.txt");
foreach (string line in File.ReadLines(fileName))
{
if (!String.IsNullOrWhiteSpace(line))
{
if (Int32.TryParse(line, out int year))
{ // We have a year
if (!_carsByYear.ContainsKey(year))
{
cars = new SortedSet<string>();
_carsByYear.Add(year, cars);
}
else
{
cars = _carsByYear[year];
}
}
else
{ // We have a car
if (!cars.Contains(line))
{
cars.Add(line);
}
}
}
}
listBox1.DataSource = _carsByYear.Keys.ToList();
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex != -1)
{
listBox2.DataSource = _carsByYear[(int)listBox1.SelectedItem].ToList();
}
}
private void button2_Click(object sender, EventArgs e)
{
if (listBox1.SelectedIndex != -1 && listBox2.SelectedIndex != -1)
{
int year = (int)listBox1.SelectedItem;
string car = listBox2.SelectedItem.ToString();
label1.Text = year.ToString();
label2.Text = car;
}
else
{
label1.Text = "";
label2.Text = "";
}
}
If you still can't get it to work, give MORE DETAILS about the contents of the file and how you're supposed to use it in your interface.

Winforms insert image into ListView / ImageList at index

Winforms, C#, VS2017
ImageList does not have an Insert method (however ListViewItemCollection does). I have tried a few different ways to insert a new image into the middle of a ListView and it's LargeImageList, but not getting it to work quite properly.
Anyone have any tried and true code that works properly?
This is what I have, but the images don't get synced properly to the items in the list.
protected void InsertThumbnail(string key, string keySelected)
{
var newImageList = new ImageList()
{
ImageSize = new Size(thumbWidth, thumbHeight)
};
var itemNew = new ListViewItem();
var foundSelected = false;
//lvAllPages.BeginUpdate();
for (int i = 0; i < lvAllPages.Items.Count; i++)
{
var item = lvAllPages.Items[i];
newImageList.Images.Add(item.Tag.ToString(), lvAllPages.LargeImageList.Images[i]);
if (item.Tag.ToString() == keySelected)
{
var image = batch.GetThumbnail(key);
newImageList.Images.Add(key, image);
itemNew = new ListViewItem()
{
BackColor = Color.Aquamarine,
ImageIndex = i,
Tag = key,
};
if (isLocal)
itemNew.Text = $"{GetFileName(key)} (insert) - {itemNew.ImageIndex}";
foundSelected = true;
}
if (foundSelected)
{
item.ImageIndex = item.ImageIndex + 1;
if (isLocal)
item.Text = $"{GetFileName(item.Tag.ToString())} - {item.ImageIndex}";
}
}
lvAllPages.LargeImageList.Dispose();
lvAllPages.LargeImageList = newImageList;
lvAllPages.Items.Insert(itemNew.ImageIndex, itemNew);
}
One more related thing, but not pertinent to the problems I am having. For anyone looking at this question and having similar issues, this helped with the issue of sorting items after inserting a new one. Default behavior when you insert a new ListViewItem at a given index, it will appear at the bottom of the list. I found this handy class to keep items sorted by index, which solved that problem:
class CompareByIndex : IComparer
{
private readonly ListView _listView;
public CompareByIndex(ListView listView)
{
this._listView = listView;
}
public int Compare(object x, object y)
{
int i = this._listView.Items.IndexOf((ListViewItem)x);
int j = this._listView.Items.IndexOf((ListViewItem)y);
return i - j;
}
}
And in the form load:
lvAllPages.ListViewItemSorter = new CompareByIndex(lvAllPages);
Obviously, that's a design decision. ImageList.Images is a ImageCollection and as such, it implements the IList interface.
Unfortunately, the Insert() method is allowed to throw a NotSupportedException. And that's what the list will do when used like a IList:
((IList)imageList.Images).Insert(5, new Bitmap(10,10));
System.NotSupportedException: 'Specified method is not supported.'
In order to have the images shown in a specific order, use the Add() method which takes the key:
imageList.Images.Add("1", new Bitmap(100,100));
That should also enable you to replace the image:
imageList.Images.RemoveByKey("1");
imageList.Images.Add("1", new Bitmap(200,200));
For that to work, you need to set the Sorting property:
listView1.Sorting = SortOrder.Ascending;
For storing additional information like path etc. use anotther data structure with the same key.
Here's the code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ImageList imageList = new ImageList();
Dictionary<string, Metadata> metadata = new Dictionary<string, Metadata>();
private string dir = #"H:\temp";
private void button1_Click(object sender, EventArgs e)
{
// You would set this in the designer, probably
listView1.Sorting = SortOrder.Ascending;
listView1.View = View.LargeIcon;
listView1.LargeImageList = imageList;
// Make sure we start from the beginning
listView1.Items.Clear();
imageList.Images.Clear();
metadata.Clear();
// Add items
for (int i = 0; i < 10; i++)
{
var filename = "1 ("+(i+1)+").png"; // Just strange names I have
var fullFileName = Path.Combine(dir, filename);
imageList.Images.Add(i.ToString(), Bitmap.FromFile(fullFileName));
metadata.Add(i.ToString(), new Metadata{Path = fullFileName});
listView1.Items.Add(i.ToString(), "Image " + i, i.ToString());
}
// Update view
listView1.Refresh();
listView1.Invalidate();
}
private void button2_Click(object sender, EventArgs e)
{
for (int i = 3; i < 6; i++)
{
var filename = "1 ("+(i+2)+").png";
var fullFileName = Path.Combine(dir, filename);
// Change image
imageList.Images.RemoveByKey(i.ToString());
imageList.Images.Add(i.ToString(), Bitmap.FromFile(fullFileName));
// Match metadata and image
metadata[i.ToString()] = new Metadata{Path = fullFileName};
}
listView1.Refresh();
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
var key = listView1.SelectedItems[0].ImageKey;
label1.Text = metadata[key].Path;
}
else
{
label1.Text = "No image selected";
}
}
}
internal class Metadata
{
internal string Path;
}

Firing DropDownList.SelectedIndexChanged event when enableViewState = false

I have a DropDownList control which really don't want to enable ViewState for as the item list is readily available from the server.
In this situation a post-back will obviously show an empty Items list, but at the same time I want the SelectedIndexChanged event to fire (using AutoPostBack)
The DropDownList control is actually dynamically created as part of a Composite Control which created an arbitrary number of DDLs - some of whose Items are sourced from the ASPX file (composite control contents) and others whose Items are bound to a data source. I am hoping that this complication isn't the source of the problem.
My thinking is that I should bind the list data to the Items collection on initial PageLoad and also rebind it late on PostBacks but I am not sure when. I am also not sure if the SelectedIndexChanged event handler will get called if on PostBack there is an empty Items list again.
Because it is part of a CompositeControl, I wonder if I should store some additional information in Control State. Would implementing something in the Conposite Control's Save/LoadControlState, Save/LoadViewState, RaisePostDataChangedEvent or RaisePostbackEvent be the solution?
Maybe I should rebind the Item list again early on PostBack e.g.before PageLoad?
Any pointers will be appreciated.
Thanks
Code provided below (cut out most of what is not relevant to problem)
Page ASPX
Note that I want to populate the ListItems of the { Group, Location, Division and BusinessUnit } DropDownLists dynamically with the items not being in dumped to ViewState but { Enabled } DDL is the static items defined below.
<cc1:FilterBar ID="FilterBar1" runat="server" CssClass="filterbar" OnFilterChanged="OnFilterChanged">
<cc1:Filter ID="Group" Label="Group" Type="DropDownList" />
<cc1:Filter ID="Location" Label="[Location]" Type="DropDownList" />
<cc1:Filter ID="Division" Label="[Division]" Type="DropDownList" />
<cc1:Filter ID="BusinessUnit" Label="[Business Unit]" Type="DropDownList" />
<cc1:Filter ID="Enabled" Label="Users" Type="DropDownList">
<asp:ListItem Value="X" Text="All"></asp:ListItem>
<asp:ListItem Value="1" Text="Active Only"></asp:ListItem>
<asp:ListItem Value="0" Text="Archived Only"></asp:ListItem>
</cc1:Filter>
</cc1:FilterBar>
Page Code Behind
protected void Page_Load(object sender, EventArgs e)
{
//if (!Page.IsPostBack) // whether to restire BindFilterBar() to first load or not?
BindFilterBar();
}
protected void BindFilterBar()
{
var h = new FilterBarBindHelper(FilterBar1);
h.AutoBindLocation(Filter.UserLocation.ID);
h.AutoBindDivision(Filter.UserDivision.ID);
h.AutoBindBusinessUnit(Filter.UserBusinessUnit.ID);
h.AutoBindGroup(Filter.UserGroup.ID);
var filter = FilterBar1.GetFilterByID("Enabled");
filter.SelectedValue = Filter.UserEnabledAsChar.ToString();
}
protected void OnFilterChanged(object sender, FilterChangedEventArgs e)
{
Debug.WriteLine($"[CompletionResults.aspx] OnFilterChanged(e={{FilterID={e.FilterID}; NewValue={e.NewValue} NewText={e.NewText}}})");
switch(e.FilterID)
{
case "Enabled":
Filter.UserEnabledAsChar = e.NewValue;
break;
case "Group":
if (e.NewValueAsInt == null)
Filter.UserGroup.Reset();
else
Filter.UserGroup.Set((int)e.NewValueAsInt, e.NewText);
break;
case "Division":
if (e.NewValueAsInt == null)
Filter.UserDivision.Reset();
else
Filter.UserDivision.Set((int)e.NewValueAsInt, e.NewText);
break;
case "BusinessUnit":
if (e.NewValueAsInt == null)
Filter.UserBusinessUnit.Reset();
else
Filter.UserBusinessUnit.Set((int)e.NewValueAsInt, e.NewText);
break;
case "Location":
if (e.NewValueAsInt == null)
Filter.UserLocation.Reset();
else
Filter.UserLocation.Set((int)e.NewValueAsInt, e.NewText);
break;
default:
return;
}
// Update Selection Text
BindSelectionText();
// Update the Grid
BindGrid();
}
/// <summary>
/// User has selected a new Page number from the UserGrid
/// </summary>
protected void OnPageChanged(object sender, EventArgs args)
{
Filter.ShowAllRows = false;
Filter.PageIndex = UserGrid.PageIndex;
BindGrid();
}
protected void OnAction(object sender, ToolbarActionClickedEventArgs args)
{
if (args.ActionValue == "email")
OnEmail();
}
FilterBarBindHelper.cs
public class FilterBarBindHelper
{
private readonly FilterBar _filterBar;
private readonly OrganisationProperties _orgProps;
public FilterBarBindHelper(FilterBar filterBar)
{
if (filterBar == null)
throw new ArgumentNullException(nameof(filterBar));
_filterBar = filterBar;
_orgProps = ObjectCache.GetOrganisationProperties();
}
/// <summary>
/// Binds Group list data to Filter, optionally creating the Filter if it doesn't exist
/// </summary>
/// <param name="selectedID">ID of currently selected Group to filter by (0 or null if none)</param>
/// <param name="createFilter">Create the Filter if not found</param>
public void AutoBindGroup(int? selectedID, bool createFilter = true)
{
// All Organisations have Groups.
// Only populate if a FilterBar Filter with ID="Groups" can be found or if createFilter = true
var f = _filterBar.GetFilterByID("Group");
if (f == null)
if (createFilter)
f = CreateFilter("Group", "Group");
else
return;
// Populate Filter list with items
var src = GroupCache.Get();
f.Items.Clear();
f.Items.Add(Any());
f.Items.AddRange(src.Select(s => new ListItem() { Value = s.StringID, Text = s.Name }).ToArray());
// Assign localised name
f.Label = _orgProps.GroupNm;
// Select
if((selectedID ?? 0) != 0)
f.SelectedValue = selectedID.Value.ToString();
_filterBar.RefreshFilter(f);
}
/// <summary>
/// Create a FilterBar Filter and add it to the FilterBar
/// </summary>
/// <param name="filterID">ID of filter to add</param>
/// <param name="label">Filter's label</param>
/// <param name="type">Filter's type</param>
/// <returns>New Filter</returns>
private Filter CreateFilter(string filterID, string label, FilterType type = FilterType.DropDownList)
{
var f = new Filter() { ID = filterID, Type = type, Label = label };
_filterBar.Filters.Add(f);
return f;
}
private ListItem Any()
{
return new ListItem("Any", "X");
}
}
Toolbar.cs
[
AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
DefaultProperty("Items"),
ParseChildren(true, "Items"),
ToolboxData("<{0}:Toolbar runat=server />"),
Designer(typeof(ToolbarDesigner))
]
public class Toolbar : CompositeControl
{
private string _preText = "Actions: ";
private bool _showRight = true;
private readonly List<ToolbarItem> _list = new List<ToolbarItem>();
public Toolbar()
{
PreText = "Actions: ";
ObjectNameSingle = "Item";
ObjectNamePlural = "Items";
ShowRight = true;
}
protected override HtmlTextWriterTag TagKey { get { return HtmlTextWriterTag.Div; } }
[
Category("Behavior"),
Description("The Item collection"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(ToolbarCollectionEditor), typeof(UITypeEditor)),
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public List<ToolbarItem> Items
{
get { return _list; }
}
//various properties (snip)
protected override void RenderContents(HtmlTextWriter writer)
{
if(_leftSide != null)
_leftSide.RenderControl(writer);
if(_rightSide != null)
_rightSide.RenderControl(writer);
if(_leftSide == null && _rightSide == null && DesignMode)
writer.Write("No Toolbar Items have been set up in designer");
}
public void RebuildChildControls()
{
// Indicate that the child controls need rebuilding
// Ref: http://yourdotnetdesignteam.blogspot.co.uk/2008/09/life-cycle-of-aspnet-controls_28.html "Composite Controls" section:
// "Note 1: When the Composite Control is displayed normally, 'CreateChildControls' is called AFTER the 'Load' method.
// However, when a post back event occurs, 'CreateChildControls' is called AFTER the 'Init' method.
// This certainly makes the 'CreateChildControls' method an "interesting" aspect of the Life Cycle."
// So on postback, the calling method should call RebuildChildControls() after repopulating/modifying Filter Items
ChildControlsCreated = false;
//RecreateChildControls(); this will happen in due course anyway
}
// Controls in Composite Control
private ToolbarActionContainer _leftSide;
private WebControl _rightSide;
private ToolbarActionItem _liPreText;
private Literal _litPreText;
private HtmlGenericControl _spanRowCount;
private HtmlGenericControl _spanPageCount;
private DropDownList _ddlPage;
private Literal _litPageCount;
protected override void CreateChildControls()
{
Controls.Clear();
_leftSide = new ToolbarActionContainer(); // UL
_rightSide = new WebControl(HtmlTextWriterTag.Div);
_liPreText = new ToolbarActionItem(ToolbarActionType.PreText);
_litPreText = new Literal() { Text = "Actions: " };
// Create the Toolbar Action Items
var actionItems = new List<ToolbarActionItem>(_list.Count);
foreach (var item in _list)
{
if (item.Visible)
{
var li = CreateToolbarActionItemControls(item);
actionItems.Add(li);
}
}
_spanRowCount = new HtmlGenericControl("span"); // "NNN entitie(s) found";
_spanPageCount = new HtmlGenericControl("span"); // "Page [DDL] of [LIT]";
_ddlPage = new DropDownList() { ID = "PageDDL", AutoPostBack = true, EnableViewState = false };
_litPageCount = new Literal();
_spanPageCount.Controls.Add(new Literal() { Text = "Page " });
_spanPageCount.Controls.Add(_ddlPage);
_spanPageCount.Controls.Add(new Literal() { Text = " of " });
_spanPageCount.Controls.Add(_litPageCount);
_liPreText.Controls.Add(_litPreText);
_leftSide.Controls.Add(_liPreText);
foreach(var item in actionItems)
_leftSide.Controls.Add(item);
_rightSide.Controls.Add(_spanRowCount);
_rightSide.Controls.Add(_spanPageCount);
Controls.Add(_leftSide);
Controls.Add(_rightSide);
_ddlPage.SelectedIndexChanged += PageDDL_SelectedIndexChanged;
base.CreateChildControls();
ChildControlsCreated = true;
UpdateRowCountText(); // Assigns the RowCount text to the span control _spanPageCount
UpdatePageCountText(); // The Y in "Page X of Y"
ApplyStandardClassNames();
CreatePageDDLItems(); // Populates Items in PageDDL (if required)
AssignPageDDLSelectedValue(); // Assigns the current PageDDL value (if required)
}
protected virtual ToolbarActionItem CreateToolbarActionItemControls(ToolbarItem item)
{
// Create List Item and add CssClass if required
var li = CreateToolbarActionItem(ToolbarActionType.Action);
if (item.HasCssClass)
li.CssClass = item.CssClass;
if (item.TextOnly)
{
// Text Only Action Items are added as literal text
li.Controls.Add(new Literal() { Text = item.Text });
}
else
{
var btn = new LinkButton() { Text = item.Text, ToolTip = item.ToolTip, CssClass = item.CssClass };
if (item.HasURLLink)
btn.Attributes.Add("href", item.URLLink);
else
{
btn.Click += LinkButton_Clicked;
_map.Add(btn, item); // used if posting back
// btn.Attributes.Add("href", "#");
// var js = MakeButtonJavaScript(item);
// if (js != string.Empty)
// btn.Attributes.Add("onclick", "javascript:" + js);
if(!string.IsNullOrEmpty(item.PrePostbackJSFunction))
btn.OnClientClick = $"return {item.PrePostbackJSFunction}(this);";
}
li.Controls.Add(btn);
}
return li;
}
protected virtual ToolbarActionItem CreateToolbarActionItem(ToolbarActionType type)
{
return new ToolbarActionItem(type);
}
private void CreatePageDDLItems()
{
// No DDL control created yet?
if (!ChildControlsCreated)
return;
var pageCount = PageCount;
// Current count is already correct?
if (pageCount == _ddlPage.Items.Count - 1) // -1 = "all"
return;
_ddlPage.Items.Clear();
_spanPageCount.Visible = (pageCount > 1); // Show this section only if multipage
// Not multi page?
if (pageCount <= 1)
return;
var li = new ListItem("All", "all");
_ddlPage.Items.Add(li);
for (var i = 0; i < pageCount; i++)
{
li = new ListItem((i + 1).ToString());
_ddlPage.Items.Add(li);
}
// AssignPageDDLSelectedValue() is already called whenever CreatePageDDLItems() is called!
//AssignPageDDLSelectedValue();
}
private void AssignPageDDLSelectedValue()
{
if (!ChildControlsCreated)
return;
if (ShowAllPages)
_ddlPage.SelectedValue = "all";
else
_ddlPage.SelectedValue = CurrentPage.ToString();
}
private void LinkButton_Clicked(object sender, EventArgs e)
{
System.Diagnostics.Debug.Assert(sender is LinkButton);
var button = sender as LinkButton;
var item = _map[button];
// Raise event with item's value
OnActionButtonClicked(item.Value);
}
private void PageDDL_SelectedIndexChanged(object sender, System.EventArgs e)
{
System.Diagnostics.Debug.Assert(sender == _ddlPage);
var v = _ddlPage.SelectedValue;
var newShowAllPages = (v == "all");
var newPage = newShowAllPages ? 0 : int.Parse(v);
// No Change?
if (newShowAllPages == ShowAllPages &&
(!newShowAllPages && (newPage == CurrentPage)))
return;
// Assign and raise event
ShowAllPages = newShowAllPages;
CurrentPage = newPage;
OnPageChanged(newShowAllPages, newPage);
}
private void OnActionButtonClicked(string id)
{
var evt = ActionClicked;
// check there are subscribers, and trigger if necessary
if (evt != null)
evt(this, new ToolbarActionClickedEventArgs(id));
}
private void OnPageChanged(bool showAll, int newPageNumber)
{
var evt = PageChanged;
// check there are subscribers, and trigger if necessary
if (evt != null)
evt(this, new ToolbarPageChangedEventArgs(showAll, newPageNumber));
}
}
public class ToolbarPageChangedEventArgs : EventArgs
{
public bool ShowAllPages { get; }
public int NewPageNumber { get; }
internal ToolbarPageChangedEventArgs(bool showAllPages, int newPageNumber)
{
ShowAllPages = showAllPages;
NewPageNumber = newPageNumber;
}
}
public class ToolbarActionClickedEventArgs : EventArgs
{
public string ActionValue { get; }
internal ToolbarActionClickedEventArgs(string value)
{
ActionValue = value;
}
}
public delegate void ToolbarPageChangedEventHandler(object sender, ToolbarPageChangedEventArgs args);
public delegate void ToolbarActionClickedEventHandler(object sender, ToolbarActionClickedEventArgs args);
ToolbarItem.cs
[TypeConverter(typeof(ExpandableObjectConverter))]
public class ToolbarItem
{
public ToolbarItem() : this(string.Empty, string.Empty, string.Empty, string.Empty)
{
}
public ToolbarItem(string text, string value, string jslink, string urllink)
{
Text = text;
Value = value;
JSLink = jslink;
URLLink = urllink;
CssClass = string.Empty;
ToolTip = string.Empty;
PrePostbackJSFunction = string.Empty;
Visible = true;
}
.... snip ...
}
public enum ToolbarActionType
{
None = 0,
PreText = 1,
Action = 2,
}

GridView missing data between postbacks

So basically I am doing a manage packaging item system. The scenario is, when I select from gvSPU, gvFinalised should display the item in database. After that, when I add new item into the gvFinalised, it supposed to keep stacking up the items instead of wiping out the previous record and display the added latest one. Here is the code:
private List<DistributionStandardPackingUnitItems> tempDistSPUI
{
get
{
if (ViewState["tempDistSPUI"] == null)
{
return new List<DistributionStandardPackingUnitItems>();
}
else
{
return (List<DistributionStandardPackingUnitItems>)ViewState["tempDistSPUI"];
}
}
set
{
ViewState["tempDistSPUI"] = value;
}
}
protected void gvSPU_OnRowCommand(object sender, GridViewCommandEventArgs e)
{
int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
int rowNo = int.Parse(e.CommandArgument.ToString());
SPUname = this.gvSPU.DataKeys[rowNo].Value.ToString();
lblSPUname.Text = SPUname;
List<DistributionStandardPackingUnitItems> templist = new List<DistributionStandardPackingUnitItems>();
templist = tempDistSPUI;
templist = packBLL.getAllDistSPUItemByDistributionIDnSPUName(distributionID, SPUname);
gvFinalised.DataSource = templist;
gvFinalised.DataBind();
this.tempDistSPUI = templist;
}
When gvSPU row is selected, it should store all the records into templist and display in gvFinalised.
List<string> prodVariantIDList = new List<string>();
private List<string> SelectedVariantDetailIDs
{
get
{
if (ViewState["SelectedVariantDetailIDs"] == null)
{
return new List<string>();
}
else
{
return (List<string>)ViewState["SelectedVariantDetailIDs"];
}
}
set
{
ViewState["SelectedVariantDetailIDs"] = value;
}
}
protected void lbnAdd_Click(object sender, EventArgs e)
{
List<ProductPacking> prodVariantDetail = new List<ProductPacking>();
int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
// get the last product variant IDs from ViewState
prodVariantIDList = this.SelectedVariantDetailIDs;
foreach (RepeaterItem ri in Repeater1.Items)
{
GridView gvProduct = (GridView)ri.FindControl("gvProduct");
foreach (GridViewRow gr in gvProduct.Rows)
{
CheckBox cb = (CheckBox)gr.FindControl("cbCheckRow");
//Prevent gvFinalised to store duplicate products
if (cb.Checked && !prodVariantIDList.Any(i => i == gvProduct.DataKeys[gr.RowIndex].Value.ToString()))
{
// add the corresponding DataKey to idList
prodVariantIDList.Add(gvProduct.DataKeys[gr.RowIndex].Value.ToString());
}
}
}
for (int i = 0; i < prodVariantIDList.Count; i++)
{
prodVariantDetail.Add(prodPackBLL.getProdVariantDetailByID(prodVariantIDList[i]));
}
gvFinalised.DataSource = prodVariantDetail;
gvFinalised.DataBind();
// save prodVariantIDList to ViewState
this.SelectedVariantDetailIDs = prodVariantIDList;
}
When add button is on click, it should append with the record in gridview instead of wiping them off and insert the checked one.
I am using the viewState to store the record between postbacks. However, when I try to add new item into gvFinalised, the previous record which in the templist will disappear and the gvFinalised will be populated with the result from prodVariantDetail list.
Any guide? Thanks in advance.
EDIT
List<DistributionStandardPackingUnitItems> itemList = new List<DistributionStandardPackingUnitItems>();
protected void gvSPU_OnRowCommand(object sender, GridViewCommandEventArgs e)
{
int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
int rowNo = int.Parse(e.CommandArgument.ToString());
SPUname = this.gvSPU.DataKeys[rowNo].Value.ToString();
lblSPUname.Text = SPUname;
itemList = tempDistSPUI;
itemList = packBLL.getAllDistSPUItemByDistributionIDnSPUName(distributionID, SPUname);
gvFinalised.DataSource = itemList;
gvFinalised.DataBind();
this.tempDistSPUI = itemList;
}
protected void lbnAdd_Click(object sender, EventArgs e)
{
List<DistributionStandardPackingUnitItems> prodVariantDetail = new List<DistributionStandardPackingUnitItems>();
int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
// get the last product variant IDs from ViewState
prodVariantIDList = this.SelectedVariantDetailIDs;
foreach (RepeaterItem ri in Repeater1.Items)
{
GridView gvProduct = (GridView)ri.FindControl("gvProduct");
foreach (GridViewRow gr in gvProduct.Rows)
{
CheckBox cb = (CheckBox)gr.FindControl("cbCheckRow");
//Prevent gvFinalised to store duplicate products
if (cb.Checked && !prodVariantIDList.Any(i => i == gvProduct.DataKeys[gr.RowIndex].Value.ToString()))
{
// add the corresponding DataKey to idList
prodVariantIDList.Add(gvProduct.DataKeys[gr.RowIndex].Value.ToString());
}
}
}
for (int i = 0; i < prodVariantIDList.Count; i++)
{
prodVariantDetail.Add(packBLL.getProdVariantDetailByID(prodVariantIDList[i]));
}
for (int j = 0; j < itemList.Count; j++)
{
prodVariantDetail.Add(itemList[j]);
}
gvFinalised.DataSource = prodVariantDetail;
gvFinalised.DataBind();
}
// save prodVariantIDList to ViewState
this.SelectedVariantDetailIDs = prodVariantIDList;
}
You have to add the elements of tempDistSPUI into prodVariantDetail before binding prodVariantDetail to gvFinalised.
Here's what I would do using List.AddRange Method:
protected void lbnAdd_Click(object sender, EventArgs e)
{
List<DistributionStandardPackingUnitItems> prodVariantDetail = new List<DistributionStandardPackingUnitItems>();
int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
// get the last product variant IDs from ViewState
prodVariantIDList = this.SelectedVariantDetailIDs;
foreach (RepeaterItem ri in Repeater1.Items)
{
GridView gvProduct = (GridView)ri.FindControl("gvProduct");
foreach (GridViewRow gr in gvProduct.Rows)
{
CheckBox cb = (CheckBox)gr.FindControl("cbCheckRow");
//Prevent gvFinalised to store duplicate products
if (cb.Checked && !prodVariantIDList.Any(i => i == gvProduct.DataKeys[gr.RowIndex].Value.ToString()))
{
// add the corresponding DataKey to idList
prodVariantIDList.Add(gvProduct.DataKeys[gr.RowIndex].Value.ToString());
}
}
}
for (int i = 0; i < prodVariantIDList.Count; i++)
{
prodVariantDetail.Add(packBLL.getProdVariantDetailByID(prodVariantIDList[i]));
}
// get the content of tempDistSPUI from ViewState
itemList = this.tempDistSPUI;
// add all elements of itemList to prodVariantDetail
prodVariantDetail.AddRange(itemList);
gvFinalised.DataSource = prodVariantDetail;
gvFinalised.DataBind();
// save prodVariantIDList to ViewState
this.SelectedVariantDetailIDs = prodVariantIDList;
}

how to find the selected item in list view when we are using groups in listview

I have managed this in list view for grouping items in list view i have customer table have columns with
category id
category name
categories
-----------
category name 1
category name 2
category name 3
price ranges
-----------
ALL
0-500
500-1000
I have done above task but i have problem with checking selected item in groups in list view ..
my problem is how we fire the event like if i select the first item in first group in list view i want to do something ....
and if i select the first item in second group in list view i want do something...
and some where i have to use the selected item text in events.....
how i find the checking ...
can any one help on this .....
Many thanks....
and this is my code
private void categorieslist()
{
lstviewcategories.View = View.Details;
lstviewcategories.Columns.Add(new ColumnHeader() { Width = lstviewcategories.Width - 20 });
lstviewcategories.HeaderStyle = ColumnHeaderStyle.None;
lstviewcategories.Sorting = SortOrder.Ascending;
lstviewcategories.Dock = DockStyle.None;
ListViewGroup categorygroup = new ListViewGroup("Category Types",HorizontalAlignment.Center);
lstviewcategories.Groups.Add(categorygroup);
var categorytypes = (from categories in abc.categories
select categories.category_Name).ToList();
lstviewcategories.Items.Add(new ListViewItem() { Text = "ALL", Group = categorygroup });
foreach (string item in categorytypes)
{
lstviewcategories.Items.Add(new ListViewItem() { Text = item.ToString(), Group = categorygroup });
}
ListViewGroup pricerangegroup = new ListViewGroup("Price Ranges", HorizontalAlignment.Center);
lstviewcategories.Groups.Add(pricerangegroup);
lstviewcategories.Items.Add(new ListViewItem() { Text = "ALL", Group = pricerangegroup });
lstviewcategories.Items.Add(new ListViewItem() { Text = "0-500", Group = pricerangegroup });
lstviewcategories.Items.Add(new ListViewItem() { Text = "500-1000", Group = pricerangegroup });
lstviewcategories.Items.Add(new ListViewItem() { Text = "1000+", Group = pricerangegroup });
}
EDIT :
private void lstviewcategories_SelectedIndexChanged(object sender, EventArgs e)
{
// int index = 0;
if (lstviewcategories.SelectedItems.Count > 0 &&lstviewcategories.SelectedItems[0].Group.Name == "Category Types")
{
string text = lstviewcategories.SelectedItems[0].Text.ToString();
var categorywithids = (from categorytypes in abc.categories
where categorytypes.category_Name.Equals(text)
select categorytypes.category_Id).SingleOrDefault();
var productcategoty = from productswithcatgories in abc.product1
where productswithcatgories.category_Id.Equals(categorywithids)
select new
{
productid = productswithcatgories.product_Id, //0
productnam = productswithcatgories.product_Name, //1
productimage = productswithcatgories.product_Image, //2
productprice = productswithcatgories.product_Price,//3
productdescr = productswithcatgories.product_Description,//4
};
productbindingsource.DataSource = productcategoty;
productgridview.DataSource = productbindingsource;
productgridview.Columns[0].Visible = false;
productgridview.Columns[4].Visible = false;
}
}
Try creating a class derived from ListViewItem and add an enumeration property which you can query in the SelectedIndexChanged event:
public class CustomListViewItem : ListViewItem
{
public CustomListViewItemType Type { get; set; }
}
public enum CustomListViewItemType
{
Type1 = 0,
Type2 = 1
}
lstviewcategories.Items.Add(new CustomListViewItem() { Text = "ALL", Group = pricerangegroup, Type = CustomListViewItemType.Type2 });
void lstviewcategories_SelectedIndexChanged(object sender, EventArgs e)
{
if (lstviewcategories.SelectedItems.Count > 0)
{
CustomListViewItem customListItem = (CustomListViewItem)lstviewcategories.SelectedItems[0];
switch (customListItem.Type)
{
case CustomListViewItemType.Type1:
{
//...
}break;
case CustomListViewItemType.Type2:
{
//...
}break;
}
}
}
You can get SelectedItems for example in SelectedIndexChanged event and check group like below:
private void lstviewcategories_SelectedIndexChanged(object sender, EventArgs e)
{
if(lstviewcategories.SelectedItems.Count > 0 && lstviewcategories.SelectedItems[0].Group.Name == "group name")
//do smth
}
if MultiSelect property is enabled and for example you want to check selected items on some kind button click, loop through all selected items:
private void button_Click(object sender, EventArgs e)
{
foreach (ListViewItem item in lstviewcategories.SelectedItems)
{
if(item.Group.Name == "group name")
//do smth
}
}

Categories