How I can realize parallel search in ObservableCollection? - c#

I have an ObservableCollection, where Item has 2 properties(for example: Name and Id) and collection contains of 12k elements. So, i have a textbox, i want to search elements, which names contains my textbox value and add these elems in new collection.
in real-proj:
Silverlight, TreeView(its ItemSource is my collection) which dynamically changing. And TreeView changing in UI.
My problem is just in slowly rendering results of search. I thing if it'll be parallel - it saves me.
for example, some code im using:
private ObservableCollection<ICDDocumentItemViewModel> LinearSearch(string searchText)
{
var filteredCollection = new ObservableCollection<ICDDocumentItemViewModel>();
if (searchText.Length > 3)
{
foreach (var itemViewModel in _linearCollection)
{
if (!itemViewModel.Model.Name.ToLower().Contains(searchText.ToLower())) continue;
if (itemViewModel.Children.Count != 0)
{
itemViewModel.IsExpanded = true;
}
filteredCollection.Add(itemViewModel);
}
}
if(searchText.Length <= 3)
{
return new ObservableCollection<ICDDocumentItemViewModel>(ICDItemsViewModelsMain);
}
return filteredCollection;
}

there is no need to have parallel processing in place normally, this code should help you here.
private ObservableCollection<ICDDocumentItemViewModel> GetFiltered(string filter)
{
ObservableCollection<ICDDocumentItemViewModel> filteredCollection;
if (filter.Length > 3)
{
filteredCollection = new ObservableCollection<ICDDocumentItemViewModel>(_linearCollection.Where(x => x.Name.ToLower().Contains(filter)));
filteredCollection.ToList().ForEach(DetectChildren);
}
else
{
filteredCollection = new ObservableCollection<ICDDocumentItemViewModel>();
}
return filteredCollection;
}
private void DetectChildren(ICDDocumentItemViewModel item)
{
item.IsExpanded = item.Children.Any();
}

Related

How to return processed collection on ListView xamarin

I want to check with if statement and want to display only these values which are checked on the listview.
` public void MarkerPressed2()
{
MessagingCenter.Subscribe<object, IEnumerable<AlertLevelOnClick>>(this, "PinInfo", (sender, arg) =>
{
lstLevel2.ItemsSource = arg;
var listAlert = new List<AlertLevelOnClick>();
foreach (var item in arg)
{
var currentData = new AlertLevelOnClick() {
dateForecastOnClick = item.dateForecastOnClick,
levelForecastOnClick = item.levelForecastOnClick
};
listAlert.Add(currentData);
if (item.levelForecastOnClick == 1)
{
//how to return every rows on arg or on listview lstLevel2.ItemsSource = arg; with checked
//item.levelForecastOnClick and item.dateForecastOnClick on the listView like
var test = 5;
}
else if (item.levelForecastOnClick == 2)
{
//how to return every rows on arg or on listview lstLevel2.ItemsSource = arg; with checked
//item.levelForecastOnClick and item.dateForecastOnClick on the listView like
}
}
});
}
With this code: lstLevel2.ItemsSource = arg; I fill the listview but I want to check first if the levelForecastOnClick == 1 and want to display only values which is 1 and his date dateForecastOnClick
How it's possible to return check arg collection on lstLevel2.ItemsSource ?
// create an empty list
var listAlert = new List<AlertLevelOnClick>();
foreach (var item in arg)
{
// if an item meets whatever conditions you want to test for
if (item.levelForecastOnClick == 1 && ...)
{
// add it to the list
listAlert.Add(item);
}
}
// assign your filtered list to the ListView ItemsSource
lstLevel2.ItemsSource = listAlert;

Comparing Two Collections data with each other

I have two observable collections. 1. TruckItems 2. TruckItemsComparison. Both are exactly the same.
I load data into the first TruckItems collection from EF6, then 10 seconds later I load data into the second collection TruckItemsComparison. Now the new data that was added in my 2nd collection might have been updated lately from another source and I need to only add the latest data that does not yet exist in my first collection.
I want to check if ANY of the id's from my 2nd collection does not match any of the id's in my first collection and then only add the items that does not match.
CODE:
Here is where I load my data:
private async void LoadTrucks()
{
using (TruckServiceClient service = new TruckServiceClient())
{
var items = await service.GetTrucksAsync();
if (TruckItems.Count == 0)
{
foreach (var item in items)
{
TruckItems.Add(new TruckItems
{
TruckId = item.TruckId,
TruckQuoteId = item.QuoteId,
TruckPhaseId = item.CurrentPhaseId,
TruckChassisManufacturer = item.ChassisManufacturer,
TruckChassisModel = item.ChassisModel,
TruckStatus = item.Status,
TruckJobNumber = item.JobNumbers,
TruckAddedBy = item.AddedBy,
TruckClientName = item.ClientName,
TruckClientSurname = item.ClientSurname,
TruckClientDetail = item.ClientDetail,
TruckCurrentPhase = item.CurrentPhase
});
}
}
foreach (var item in items)
{
TruckItemsComparison.Add(new TruckItems
{
TruckId = item.TruckId,
TruckQuoteId = item.QuoteId,
TruckPhaseId = item.CurrentPhaseId,
TruckChassisManufacturer = item.ChassisManufacturer,
TruckChassisModel = item.ChassisModel,
TruckStatus = item.Status,
TruckJobNumber = item.JobNumbers,
TruckAddedBy = item.AddedBy,
TruckClientName = item.ClientName,
TruckClientSurname = item.ClientSurname,
TruckClientDetail = item.ClientDetail,
TruckCurrentPhase = item.CurrentPhase
});
}
}
}
And here is where I want to compare my two collections:
public void UpdateTrucks()
{
LoadTrucks();
if (TruckItems.Count != 0)
{
var truckItemsId = TruckItems.Where(x => x.TruckId != 0).First().TruckId;
foreach (var item in TruckItemsComparison.Where(x => x.TruckId != truckItemsId))
{
TruckItems.Add(item);
}
}
}
My problem is that it adds the data from both the two collections together, regardless if the id's correspond or not. Clearly my logic here does not work, so can anyone please show me a way of how I can compare the data and only insert id's that do not yet exist in my TruckItems collection. Thanks and please let me know if you need any more information.
You can enumerate through each of the items in your TruckItemsComparison by using Except:
public void UpdateTrucks()
{
LoadTrucks();
if (TruckItems.Count != 0)
{
foreach (var item in TruckItemsComparison.Except(TruckItems))
{
TruckItems.Add(item);
}
}
}
If all you want to do is compare the Ids of your TruckItems then you can implement your own IEqualityComparer:
internal class TruckItemsComparer : IEqualityComparer<TruckItems>
{
#region IEqualityComparer Members
public bool Equals(TruckItems x, TruckItems y)
{
return (((x == null) && (y == null)) ||
((x != null) && (y != null) && x.TruckId == y.TruckId));
}
public int GetHashCode(TruckItems obj)
{
return obj. TruckId.GetHashCode();
}
#endregion
}
And then use like so:
foreach (var item in TruckItemsComparison.Except(TruckItems, new TruckItemsComparer()))

How to stop Custom OnSaving event after first saving in SItecore?

I am trying to stop my custom OnSaving event after it has been applied to the first item in the save chain.
but so far I have not been able to, and I end up with a stackoverflow exception.
Is there a simple way of doing this ?
Best regards,
Robin
private void AddOrRemoveRedirectingItemIdFromSavingItemIdList(Item savingItem, SitecoreEventArgs sitecoreEventArgs)
{
ItemLink[] referers = Globals.LinkDatabase.GetReferrers(savingItem);
var guidList = new List<ID>();
foreach (ItemLink link in referers)
{
// checking the database name of the linked Item
if (!link.SourceDatabaseName.Equals(Context.ContentDatabase.Name, StringComparison.CurrentCultureIgnoreCase))
{
continue;
}
Item item = Context.ContentDatabase.Items[link.SourceItemID, savingItem.Language];
// adding the Item to an array if the Item is not null
if (item == null || item.Fields["301Redirect"] == null || item.Fields["301RedirectedTo"] == null)
{
continue;
}
// Update the saving item ids
CheckboxField redirectField = item.Fields["301Redirect"];
if (redirectField.Checked)
{
guidList.Add(item.ID);
}
}
if (guidList.Any())
{
this.SaveIDsToEditingItem(savingItem, guidList, false);
}
}
private void SaveIDsToEditingItem(Item editingItem, IEnumerable<ID> guidList, bool forceModified)
{
Field redirectedToFromItemId = editingItem.Fields["301RedirectedToFromItemId"];
using (new EditContext(editingItem))
{
// Saving the redirected items ids
string redirectedToFromItemIdOld = redirectedToFromItemId.Value;
string redirectedToFromItemIdNew = string.Join("\n", guidList.Select(guid => guid.ToString()));
// if the values are not changed
if (redirectedToFromItemIdNew.Equals(redirectedToFromItemIdOld))
{
return;
}
redirectedToFromItemId.Value = redirectedToFromItemIdNew;
if (forceModified)
{
editingItem.RuntimeSettings.ForceModified = true;
}
}
}
}
You can do this 2 ways. The better way would be to remove the using (new EditingContext(editingItem) section from the SaveIDsToEditingItem. In the OnItemSaving event, any changes made to the savingItem would be kept.
Alternatively, if you need to use the editing context for some reason you need to use an EventDisabler in your SaveIDsToEditingItem method:
private void SaveIDsToEditingItem(Item editingItem, IEnumerable<ID> guidList, bool forceModified)
{
Field redirectedToFromItemId = editingItem.Fields["301RedirectedToFromItemId"];
using (new EventDisabler())
{
using (new EditContext(editingItem))
{
// Saving the redirected items ids
string redirectedToFromItemIdOld = redirectedToFromItemId.Value;
string redirectedToFromItemIdNew = string.Join("\n", guidList.Select(guid => guid.ToString()));
// if the values are not changed
if (redirectedToFromItemIdNew.Equals(redirectedToFromItemIdOld))
{
return;
}
redirectedToFromItemId.Value = redirectedToFromItemIdNew;
if (forceModified)
{
editingItem.RuntimeSettings.ForceModified = true;
}
}
}
}
This will prevent the OnSaving event from being fired again.

WP8 LongListMultiSelector Can't Remove Selected Items

I have a LongListMultiSelector which is binded to an ObservableCollection. When I select all items in the list and try to delete as so it starts failing and returns false after 35 successful removes.
int failed = 0;
while ((App.ViewModel.Queue.Count - failed)> 0)
{
//get playlist viewmodel
bool success = App.ViewModel.Queue.Remove((ItemViewModel)QueueList.SelectedItems[0]);
if (!success)
failed++;
System.Diagnostics.Debug.WriteLine("DELETING " + success);
}
If I do not include the check for failed items it gets stuck in an endless loop. After the task completes, 35 of the 300 items are removed. If I re-run the task another 35 items get removed and the remaining fail...
My Observable collection is defined like so
public ObservableCollection<ItemViewModel> Queue { get; set; }
this.Queue = new ObservableCollection<ItemViewModel>();
In my xaml the MultiSelector is defined like this
<toolkit:LongListMultiSelector
x:Name="QueueList"
Margin="0,0,-12,0"
ItemsSource="{Binding Queue}"
LayoutMode="List"
SelectionChanged="QueueList_SelectionChanged">
How the Queue is populated (selected items from one list are copied to the Queue
foreach (ItemViewModel item in OriginalList.SelectedItems)
{
Boolean isQueued = false;
foreach (ItemViewModel queueItem in App.ViewModel.Queue)
{
if (queueItem.Equals(item))
{
isQueued = true;
break;
}
}
ItemViewModel newItem = new ItemViewModel();
newItem = item;
if (!isQueued)
{
App.ViewModel.Queue.Add(newItem);
for (int i = 0; i < ApplicationBar.MenuItems.Count; i++)
{
ApplicationBarMenuItem menuItem = (ApplicationBarMenuItem)ApplicationBar.MenuItems[i];
if (menuItem.Text.Equals("clear queue") && !menuItem.IsEnabled)
menuItem.IsEnabled = true;
}
}
}
OriginalList.SelectedItems.Clear();
DataSerializer.SaveQueue();
}
Iterate array of SelectedItems and remove items one by one. Example:
public void delete()
{
while (Queue.SelectedItems.Count > 0)
{
Queue.ItemsSource.Remove(Queue.SelectedItems[0]);
}
}
You can also use the Clear method, which will iterate over the array and unselect the selected items.
private void Cancel_Selected(object sender, System.Windows.Input.GestureEventArgs e)
{
Queue.SelectedItems.Clear();
}

Refresh UltraGrid's GroupBy Sort on child bands when ListChanged?

I am using Infragistics 2009 vol 1.
My UltraGrid is bound to a BindingList of business objects "A" having themself a BindingList property of business objects "B". It results in having two bands: one named "BindingList`1", the other one "ListOfB" thanks to the currency manager.
I would like to refresh the GroupBy sort of the grid whenever a change is performed on the child band through the child business object and INotifyPropertyChange.
If I group by a property in the child band which is a boolean (let's say "Active") and I subscribe to the event ListChanged on the bindinglist datasource with this event handler:
void Grid_ListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.ItemChanged)
{
string columnKey = e.PropertyDescriptor.Name;
if (e.PropertyDescriptor.PropertyType.Name == "BindingList`1")
{
ultraGrid.DisplayLayout.Bands[columnKey].SortedColumns.RefreshSort(true);
}
else
{
UltraGridBand band = ultraGrid.DisplayLayout.Bands[0];
UltraGridColumn gc = band.Columns[columnKey];
if (gc.IsGroupByColumn || gc.SortIndicator != SortIndicator.None)
{
band.SortedColumns.RefreshSort(true);
}
ColumnFilter cf = band.ColumnFilters[columnKey];
if (cf.FilterConditions.Count > 0)
{
ultraGrid.DisplayLayout.RefreshFilters();
}
}
}
}
the band.SortedColumns.RefreshSort(true) is called but It gives unpredictable results in the groupby area when the property Active is changed in the child band:
if one object out of three actives becomes inactive it goes from:
Active : True (3 items)
To:
Active : False (3 items)
Instead of (which is the case when I drag the column back and forth to the group by area)
Active : False (1 item)
Active : True (2 items)
Am I doing something wrong?
Is there a way to restore the expanded state of the rows when performing a RefreshSort(true); ?
Sounds like a bug to me - you should file one with Infragistics.
As to a workaround - this is not a nice solution and I haven't tested it but you could always try saving the sort-by (group) columns to a temp store, RefreshSort() on the band, then re-apply the sort-by (gorup) columns, and sort again?
ie. Remove group-by, then re-apply.
Nasty, but it might get you out of a bind.
Well, this is how I manage to solve the problem
var ultraGridBand = this.ExperimentGrid.DisplayLayout.Bands[0];
int nbGroup = ultraGridBand.Columns.All.Count(obj => ((UltraGridColumn) obj).IsGroupByColumn);
//if (ultraGridBand.Columns.All.Any(obj => ((UltraGridColumn)obj).SortIndicator != SortIndicator.None)))
if (nbGroup == 0)//no grouping
ultraGridBand.SortedColumns.RefreshSort(true);
else if (nbGroup > 0)
{
var expandedRows = new List<ExpandedRow>();
var rowLevel1 = this.ExperimentGrid.DisplayLayout.Rows;
ExtractExpandedRows(expandedRows, rowLevel1);
ultraGridBand.SortedColumns.RefreshSort(true);
SetExpandedRows(expandedRows, rowLevel1);
}
private static void SetExpandedRows(IEnumerable<ExpandedRow> expandedRows, RowsCollection rowLevel)
{
foreach (object obj in rowLevel.All)
{
var row = obj as UltraGridGroupByRow;
if (row != null)
{
var expandedRow = expandedRows.FirstOrDefault(x => x.Value == row.ValueAsDisplayText);
if (expandedRow != null)
{
row.Expanded = expandedRow.IsExpanded;
SetExpandedRows(expandedRow.SubRows, row.Rows);
}
}
}
}
private static void ExtractExpandedRows(ICollection<ExpandedRow> expandedRows, RowsCollection rowLevel)
{
foreach (object obj in rowLevel.All)
{
var row = obj as UltraGridGroupByRow;
if(row != null)
{
var expandedRow = new ExpandedRow() { Value = row.ValueAsDisplayText, IsExpanded = row.Expanded };
expandedRows.Add(expandedRow);
ExtractExpandedRows(expandedRow.SubRows, row.Rows);
}
}
}
And this is the object that contains the information
class ExpandedRow
{
public string Value { get; set; }
public bool IsExpanded { get; set; }
private readonly List<ExpandedRow> _subRows = new List<ExpandedRow>();
public List<ExpandedRow> SubRows { get { return _subRows; } }
}

Categories