I have a group item. Then, each group in group item, i put it into a listview
var Groups = query.GroupBy(query => query.Name);
foreach (var group in Groups)
{
if (group.records.Count() > 2)
{
ListView listview = new ListView();
var itemsource = new ObservableCollection<FileProperties>();
var header = "";
foreach (var item in group.records)
{
header = item.Name;
itemsource.Add(new FileProperties(item.Name, item.Size, item.DateModified, item.Hash, item.Path, item.IsOrigin));
}
listview.ItemsSource = itemsource;
var itemsTemplate = (DataTemplate)this.Resources["Show"];
listview.ItemTemplate = itemsTemplate;
//test is mother listview
test.Items.Add(listview);
}
}
Now, i have a question, how can i update listview UI if i change value in group items without reset mother listview
The default ListView can be grouped by using CollectionViewSource. There is no need to create a child ListView for each group of the parent ListView.
My answer here shows how to create a grouped ListView, you may take a look. Or there are a bunch of demos on internet, you can googling them.
But the most important point here is that by using the default grouped ListView, we can simply create one data collection for the whole ListView, modify the items source collection to update the grouped children automatically, we don't need to create ObservableCollections for each group any more.
Related
I have a c# menu strip with top-level menu items (TLM items). I am dynamically adding items to one of the TLM items as follows, which works great.
DataRowCollection DRC = DataAccessClass.GetData("SELECT * FROM company ORDER BY CompanyName");
ToolStripMenuItem[] items = new ToolStripMenuItem[DRC.Count];
int itemCounter = 0;
foreach (DataRow dr in DRC)
{
string nm = dr["companyname"].ToString();
int id = Convert.ToInt16(dr["companyid"].ToString());
items[itemCounter] = new ToolStripMenuItem();
items[itemCounter].Name = string.Format("menuitem{0}", itemCounter);
items[itemCounter].Text = nm;
items[itemCounter].Click += new EventHandler(MenuItemClickHandler);
itemCounter++;
}
CompanyToolStripMenuItem.DropDownItems.AddRange(items);
Once this TLM has been populated, I want to dynamically add sub-menu items to each of the dynamic menu items created above. I am similarly creating an array of ToolStripMenuItems as above, and I am trying to add them to a menu item using this, shown here for the first menu item:
CompanyToolStripMenuItem.DropDownItems[0].DropDownItems.AddRange(submenuitems);
But it isn't working. Any ideas?
When I add CompanyToolStripMenuItem.DropDownItems[0] to a watch window, it is showing a "DropDownItems" property. When I try to type it in, the auto-complete drop-down isn't exposing the property as an option.
Try casting the selected DropDownItem item to a ToolStripMenuItem:
((ToolStripMenuItem)CompanyToolStripMenuItem.
DropDownItems[0]).DropDownItems.AddRange(submenuitems);
I have a question regarding use of "Tag" :
I have a ListBox, or ListView, in which I have the name of my objects, I addes a "Tag" property to find its corresponding object :
foreach(Operation op_ass in ListOpAss1)
{
op_ass.getNom(Properties.Settings.Default.Langue);
ListViewItem item = new ListViewItem(op_ass.Nom);
item.Tag = op_ass;
listBoxAss1.Items.Add(op_ass.Nom);
}
Now what I would like, is when I select an item in my list(or several), make an action on corresponding objects. But how can I find them back?
For example I want to remove selected objects from a List, or get the list of Operation ID (without displaying ID in my list).
Looks like you are adding the property, op_ass.Nom into the listbox instead of the ListViewItem, item. Modify your code as follows:
foreach (Operation op_ass in ListOpAss1)
{
op_ass.getNom(Properties.Settings.Default.Langue);
ListViewItem item = new ListViewItem(op_ass.Nom);
item.Tag = op_ass;
// Add the list view item instead of op_ass.Nom
listBoxAss1.Items.Add(item);
}
Now you should be able to retrieve the tag from selected item/items as follows:
var operation = ((listBox1.SelectedItem as ListViewItem).Tag) as Operation;
Alternatively, you could think of using data binding as follows:
foreach (Operation op_ass in ListOpAss1)
{
op_ass.getNom(Properties.Settings.Default.Langue);
}
listBoxAss1.DataSource = ListOpAss1;
listBoxAss1.DisplayMember = "Nom";
And access the data bound object as follows:
var operation = listBox1.SelectedItem as Operation;
using foreach is kind of deprecated you can look into implemented functions in list of objects
ListOpAss1.ForEach(x=>
{
x.getNom(Properties.Settings.Default.Langue);
var item = new ListViewItem(x.Nom);
item.Tag = x;
listBoxAss1.Items.Add(x.Nom);
});
in order to select an item in a list you can use SingleOrDefalt() or Skip(count) take (count) for multiple files or you can run native querys with conditions to search the list like this
var items = collection.Where(x=> x.City == "Burgas").ToList(); //You can use select if you want only certain properties of the object to be selected
///then you can use that new item list to remove the objects from the collection list like this
items.ForEach(x=>
{
collection.Remove(x);
});
I'am currently developing an WinRT app an need a ListView ordered by date and grouped by day. The ListView is bound to an ICollectionView in my ViewModel
public Windows.UI.Xaml.Data.ICollectionView GroupedData {
get
{
return cvSource.View;
}
}
private Windows.UI.Xaml.Data.CollectionViewSource cvSource;
In my XAML I can bind then the ListView to this property:
<ListView ItemsSource="{Binding GroupedData}"
Now I'am doing some calculations and Filtering on my basicData, which is stored in a List<>. After i've done this, the grouping happens via LINQ:
var result = from DataObject in basicData
group DataObject by DataObject.Date
into date_grp orderby date_grp.Key
select date_grp;
Finally I set the source of the CollectionView to this new result and fire OnPropertyChanged
cvSource.Source = result.ToList();
OnPropertyChanged("GroupdedData");
This is working as I expected, but the ListView now selects the first element every time I populate a new source. I got rid of this as described on Stackoverflow by sellmeadog
NowI like to manually select an item. This should be the previous selected item before the source of the CollectionView is changed. What is the best way to save this previous item, see if its in the newly created CollectionView, select it and scroll to it?
Best regards
For the selecting senario, add a new property to the ViewModel in and bind SelectedItem property of the ListView to it:
public Windows.UI.Xaml.Data.ICollectionView GroupedData {
get
{
return cvSource.View;
}
}
public YourObjectType CurrentItem {
get {
return this.currentItem;
}
set {
if (this.currentItem != value) {
this.currentItem = value;
this.OnPropertyChanged("CurrentItem");
}
}
}
private YourObjectType currentItem;
private Windows.UI.Xaml.Data.CollectionViewSource cvSource;
Then before setting the source, hold a reference to the current item
var current = this.CurrentItem;
cvSource.Source = result.ToList();
this.CurrentItem = current;
assuming that your DataObjects type overrides Equals method, ListView finds and selects it in the collection. If not, you may need to add code finding it's instance in the new collection and assign it to CurrentItem property.
But by selecting the item doesn't mean ListViewScrolls to it. You may need to call ListView.BringIntoView in order to scroll to the selected item.
You need ObservableComputations. Using this library you can code like this:
private INotifyCollectionChanged _groupedData
public INotifyCollectionChanged GroupedData =>
_groupedData = _groupedData ?? basicData.Grouping(dataObject => dataObject.Date)
.Selecting(date_grp => date_grp.Key);
GroupedData reflects all the changes in the basicData collection. Do not forget to add the implementation of the INotifyPropertyChanged interface to DataObject class, so that GroupedData collection reflects the changes in dataObject.Date property. GroupedData is a singleton instance so you do not lost item selection in the ListView.
What I'm trying to do is make so it selects the whole transaction when a listview item is selected so I don't have to rebuild it from each of it's string components.
I can do
List<Transaction> Transations = getTransations();
foreach(Transaction T in Transactions ){
string[] row = {T.DatabaseIndex.ToString(), T.TimeRan.ToShortTimeString(), T.MerchantID, T.OperatorID, T.TerminalID, T.AccountNumber, T.ExpDate, T.InvoiceNumber, T.PurchaseAmount, T.AuthorizeAmount, T.AcqRefData, T.RecordNo, T.CardType, T.AuthCode, T.CaptureStatus, T.RefNo, T.ResponseOrigin, T.DSIXReturnCode, T.CmdStatus, T.TextResponse, T.UserTraceData, T.Processor};
var listViewItem = new ListViewItem(row);
listView1.Items.Add(listViewItem);
}
But that doesn't save me any work when I try to retrieve the data when the user picks it.
To be able to use the ListViewItem constructor with a string array for subitem data and actually view your subitems you need to set a details view and define list view columns beforehand.
Here is a running mockup.
I have a LongListSelector in a Windows Phone Silverlight project, that is bound to a nested ObservableCollection.
In order to get the grouping working and updating automatically, I'm using a custom group class that extends ObservableCollection.
My class structure looks like this:
Main.xaml.cs:
ObservableCollection<Group<MyViewModel>> _groups;
Group.cs:
Group<T> : ObservableCollection<T> {...}
I'm populating the groups asynchronously, using a WebClient:
WebClient wc = new WebClient();
wc.OpenReadCompleted += (sender, obj) {
// parse the response here, get list of MyModels
...
foreach (var model in models)
{
var group = _groups.SingleOrDefault(g => g.Key == model.Key);
if (group == null)
{
group = new Group<MyModel> { Key = model.Key };
_groups.Add(group);
}
group.Add(model);
}
}
All this works fine, except for binding to the LongListSelector.
The first item gets added fine, but every subsequent item added to the groups list results in an IndexOutOfBounds exception.
I've tried handling the CollectionChanged event to add the items to the group, instead of on ReadComplete, but same result.
Any help would be greatly appreciated.
Are you trying to add each item as it comes as a group. You should get the entire data and group them and assign to the longlistselector. Groping on a incremental loaded data would not work good as a new item coming in might need to be added to an existing group.
Here is a good sample on the same to use on a flat list that is readily available and grouped and assigned to longlistselector
How to display data in a grouped list in LongListSelector for Windows Phone 8
Windows Phone Series – Jump Lists