How to sort data in gridview? - c#

I am trying to sort the data in gridview
everything is working fine but numeric column(Marks) taking sorting for 1st number only
Code:
protected void gvTrHty_Sorting(object sender, GridViewSortEventArgs e)
{
try
{
this.gviewSorting(e.SortExpression);
}
catch (Exception ex)
{
string arg_15_0 = ex.Message;
}
}
private void gviewSorting(string strSortExp)
{
if (this.ViewState["dvTrain"] == null)
{
DataSet dataSet = this.BindTraining();
dv = dataSet.Tables[0].DefaultView;
}
else
{
DataSet dataSet2 = (DataSet)this.ViewState["dvTrain"];
TrainingHistory.dv = dataSet2.Tables[0].DefaultView;
}
if (TrainingHistory.sortorder)
{
TrainingHistory.sortorder = false;
TrainingHistory.dv.Sort = strSortExp + " DESC";
}
else
{
TrainingHistory.sortorder = true;
TrainingHistory.dv.Sort = strSortExp;
}
this.BindData(TrainingHistory.dv);
}
If I have values in Mark(column) in gridview
Marks----> When I click this for sorting it's taking Marks
1 1
8 1st number only sorted ---> 12
40 21
12 40
21 8

It is treating your "numerical" data as a string and doing the sort against this string value, thus "40" is less than "8".
Your options are:
Put leading zeroes on the numeric field values, which is probably a no-go for obvious reasons, this would allow the existing sort to work correctly. I suppose you could temporarily put leading zeroes and then rip them out after the sort, but this sounds like a headache.
Implement your own sorting logic, like this:
public sealed class GenericComparer<T> : IComparer<T>
{
public enum SortOrder
{
Ascending = 0,
Descending = 1
}
private string sortColumn;
private SortOrder sortingOrder;
public string SortColumn
{
get
{
return this.sortColumn;
}
}
public SortOrder SortingOrder
{
get
{
return this.sortingOrder;
}
}
public GenericComparer(string theSortColumn, SortOrder theSortingOrder)
{
this.sortColumn = theSortColumn;
this.sortingOrder = theSortingOrder;
}
public int Compare(T x, T y)
{
PropertyInfo thePropertyInfo = typeof(T).GetProperty(this.sortColumn);
IComparable object1 = (IComparable)thePropertyInfo.GetValue(x, null);
IComparable object2 = (IComparable)thePropertyInfo.GetValue(y, null);
if (this.sortingOrder == SortOrder.Ascending)
{
return object1.CompareTo(object2);
}
else
{
return object2.CompareTo(object1);
}
}
}
Now in your call to .Sort() method, you pass a new instance of this helper class (passing it the column you want to sort by and the direction you want to sort - ascending or descending).
Since the comparer logic above uses generics, you can pass whatever type you want to sort by (i.e. int, DateTime, or even entire domain objects).

Related

NReco.PivotData.TopPivotTable Take last N instead of first N

Taking the first N number of rows is pretty straightforward and works well with
var topPvtTbl = new TopPivotTable(runningPvtTbl, 3, 99);
topPvtTbl.IncludeOtherGroups = false;
Is there an inverse? My use case is that the data is returning dates in ascending order on the rows and instead of taking the first 3 dates, I want the last 3 dates. I don't see a BottomPivotTable option.
You can achieve what you want in the following way:
configure base PivotTable class to order axis with dates in reverse order (descending)
apply TopPivotTable wrapper to select only first 3 dates (= so they will be actually last 3 days)
reverse axis keys with Array.Reverse. For example, if dates are columns: Array.Reverse(topPvtTbl.ColumnKeys);
-- update --
This approach will not work if underlying table-related calculation relies on the concrete axis order (like RunningValuePivotTable). Alternatively, you can implement your own IPivotTable wrapper that takes last N items. For example:
public class LastNColumnsPivotTable : IPivotTable {
IPivotTable basePvtTbl;
public LastNColumnsPivotTable(IPivotTable pvtTbl, int lastN) {
basePvtTbl = pvtTbl;
if (basePvtTbl.ColumnKeys.Length>lastN) {
lastColumnKeys = basePvtTbl.ColumnKeys.Skip(basePvtTbl.ColumnKeys.Length - lastN).ToArray();
} else {
lastColumnKeys = basePvtTbl.ColumnKeys;
}
}
public string[] Columns { get { return basePvtTbl.Columns; } }
public string[] Rows { get { return basePvtTbl.Rows; } }
ValueKey[] lastColumnKeys;
public ValueKey[] ColumnKeys { get { return lastColumnKeys; } }
public ValueKey[] RowKeys { get { return basePvtTbl.RowKeys; } }
public IPivotData PivotData { get { return basePvtTbl.PivotData; } }
public IAggregator GetValue(ValueKey rowKey, ValueKey colKey) {
return basePvtTbl.GetValue(rowKey, colKey);
}
}

Sorting a List<> using linq in C#

I would like to do "sorting" under Datagridview ColumnHeaderMouseClick.
Accending or Decending should need to be automatic, selected column value automatic.
I gone through many websites and tried some options but I could not be able to achieve my goal.
private void lst_Install_Item_Main_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
try
{
DataGridViewColumn newColumn = lst_Install_Item_Main.Columns[e.ColumnIndex];
List<test> temp = (List<test>)lst_Install_Item_Main.DataSource;
//var newList = temp.OrderBy(m => m.feet).ToList();
//var newList = temp.AsQueryable().OrderBy(m => m.feet).ToList();
temp.Sort((m1, m2) => m1.feet.CompareTo(m2.feet));
lst_Install_Item_Main.DataSource = temp;
lst_Install_Item_Main.Refresh();
}
catch (Exception ex)
{
MessageBox.Show("There was an error bringing sorting \n" + ex.Message, "Testing", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Above code "sorting" the list on "feet" column but
I would like to pass the columnname which user clicked, is that possible ?
I have input like (1', 21', 123', 5', 10')
Above code sorting the list like >> (1', 10', 123', 21', 5')
But I want output like >> (1', 5', 10', 21', 123')
Is that possible to achieve ?
How to achieve Ascending or Descending here
(I mean while I clicked first time it will do Ascending and while click on same column second time it should need to do Descending)
Your suggestionshelp are greatly appreciated.
If you don't have negative values, then to sort as you want you need either to parse values as numeric or simply pad them:
temp.Sort((m1, m2) => m1.feet.PadLeft(2).CompareTo(m2.feet.PadLeft(2)));
When comparing strings "1", "5" and "10" this will be comparing " 1", " 5" and "10" instead (notice empty space, which is less than 0 character), making them sorted in the right order.
Make sure to chose number big enough to cover padding to the longest number.
You need to sort the values of feet as integers. To do this, you first need to remove the feet-symbol (') and afterwards parse the value to an int (temporarily, the value is still stored as a string).
This should do the trick:
temp.Sort((m1, m2) => int.Parse(m1.feet.Replace("'", "")).CompareTo(int.Parse(m2.feet.Replace("'", ""))));
Also, I would recommend that you don't store the feet-symbol in the value, and instead use some kind of formatting to include it, when showing the values in the Grid. That way you can avoid these kinds of conversions and comparisons, each time you need to use the values.
You have to convert your strings to integer-values as strings are differently ordered (lexicographically 10 comes before 2). Furtheremore as your input contains '-characters you have to delete them first using String.Trim('\'').
temp.Sort((m1, m2) => Convert.ToInt32(m1.feet.Trim('\'')).CompareTo(Convert.ToInt(m2.feet.Trim('\''))));
Alternativly you may also use Linq-OrderBy:
temp = temp.OrderBy(x => Convert.ToInt32(x.feet.Trim('\''))).ToList();
And OrderByDescending if in descending-order.
UPDATED for question # 3, added trigger for sort order
I would suggest you to use ICoparer in such way
public class TestComparer : IComparer<test>
{
bool isAscending;
public TestComparer(bool isAscendingOrder)
{
isAscending = isAscendingOrder;
}
int IComparer<test>.Compare(test a, test b)
{
int c1 = IntFromStr(a.feet);
int c2 = IntFromStr(b.feet);
int res;
res = (c1 > c2) ? 1 : (c1 < c2) ? -1 : 0;
return isAscending ? res : -res;
}
int IntFromStr(string s)
{
int result;
return (int.TryParse(s.Replace("'", ""), out result)) ? result : int.MaxValue;
}
}
this comparer will move not valid items to the end of the sorted list, also you will be able to change your sort behaviour easily, you will call it like below
List < test > lst = new List<test>();
// It will be your property to Trigger value each time you click
// (sortOrderTrigger = !sortOrderTrigger)
bool sortOrderTrigger = true;
lst.Add(new test { feet = "1'" });
lst.Add(new test { feet = "21'" });
lst.Add(new test { feet = "123'" });
lst.Add(new test { feet = "5'" });
lst.Add(new test { feet = "10'" });
lst.Add(new test { feet = "15'" });
lst.Add(new test { feet = "jj'" });
lst.Add(new test { feet = "ff'" });
lst.Sort(new TestComparer(sortOrderTrigger));
Thanks for all your help and Direction.
I have fixed my requirements as like below, Hope this help to someone like me :)
1. Created list which contains the same columns as the columns dataproperty.
public class sortList
{
public string Layer { get; set; }
public string mlenth { get; set; }
public string diameter { get; set; }
public string subtypecd { get; set; }
public string coatingtype { get; set; }
public string year { get; set; }
public string gisid { get; set; }
public string taxdistrict { get; set; }
public string lengthsource { get; set; }
public string shapelen { get; set; }
public string feet { get; set; }
public sortList()
{
this.Layer = ListSortDirection.Ascending.ToString();
this.mlenth = ListSortDirection.Ascending.ToString();
this.feet = ListSortDirection.Ascending.ToString();
this.diameter = ListSortDirection.Ascending.ToString();
this.subtypecd = ListSortDirection.Ascending.ToString();
this.coatingtype = ListSortDirection.Ascending.ToString();
this.year = ListSortDirection.Ascending.ToString();
this.gisid = ListSortDirection.Ascending.ToString();
this.taxdistrict = ListSortDirection.Ascending.ToString();
this.lengthsource = ListSortDirection.Ascending.ToString();
this.shapelen = ListSortDirection.Ascending.ToString();
}
}
2. Written code on ColumnHeaderMouseClick event and order function
private void lst_Install_Item_Main_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
try
{
//Get Column which clicked
DataGridViewColumn newColumn = lst_Install_Item_Main.Columns[e.ColumnIndex];
//Get Values from DataGrid
List<test> temp = (List<test>)lst_Install_Item_Main.DataSource;
//Get the sorting order for that column
string orderby = GetOrder(newColumn.DataPropertyName);
if (orderby == ListSortDirection.Ascending.ToString()) //Ascending
{
if (newColumn.DataPropertyName == "feet") //Feet column sort with double value and required trim
{
temp = temp.OrderBy(x => Convert.ToDouble(x.feet.Trim('\''))).ToList();
}
else if (newColumn.DataPropertyName == "shapelen") //Shapelen column sort with double value and required trim
{
temp = temp.OrderBy(x => Convert.ToDouble(x.shapelen.Trim('\''))).ToList();
}
else ///other columns having string value only.
{
temp = temp.OrderBy(x => x.GetType().GetProperty(newColumn.DataPropertyName).GetValue(x, null)).ToList();
}
}
else // Descending
{
if (newColumn.DataPropertyName == "feet") //Feet column sort with double value and required trim
{
temp = temp.OrderByDescending(x => Convert.ToDouble(x.feet.Trim('\''))).ToList();
}
else if (newColumn.DataPropertyName == "shapelen") //Shapelen column sort with double value and required trim
{
temp = temp.OrderByDescending(x => Convert.ToDouble(x.shapelen.Trim('\''))).ToList();
}
else //other columns having string value only.
{
temp = temp.OrderByDescending(y => y.GetType().GetProperty(newColumn.DataPropertyName).GetValue(y, null)).ToList();
}
}
lst_Install_Item_Main.DataSource = temp;
lst_Install_Item_Main.Refresh();
}
catch (Exception ex)
{
MessageBox.Show("There was an error while sorting \n" + ex.Message, "Closeout Calculator", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private string GetOrder(string columnName)
{
//Store the each coulmn(Ascending/Descending) values to make it dynamic
string ord = sortOrder[0].GetType().GetProperty(columnName).GetValue(sortOrder[0], null).ToString();
if (ord == ListSortDirection.Ascending.ToString())
{
sortOrder[0].GetType().GetProperty(columnName).SetValue(sortOrder[0], ListSortDirection.Descending.ToString(), null);
}
else
{ sortOrder[0].GetType().GetProperty(columnName).SetValue(sortOrder[0], ListSortDirection.Ascending.ToString(), null); }
return ord;
}
3. sortoder list initialize and obj declared at Constructor.
Private List<sortList> sortOrder = new List<sortList>();
sortOrder.Add(new sortList());

Save from overwriting large number of values by parallel calls without messing the code

class abc {
string value1 = "", value2 = "", ........... valueN = "";
#region Methods
public void method1(DataSet dataSet) {
populate valueS using populateValues() and use it for doing something
}
....
public void methodN(DataSet dataSet) {
populate valueS using populateValues() and use it for doing something else
}
#endregion
public void populateValues(DataSet dataSet) {
#region populate valueS so they can be used by methodS
if(dataSet.Tables.Contains("Table1") {
var dataRow1 = dataSet.Tables["Table1"].Select();
if(dataRow1.Length > 0) {
value1 = dataRow1[0]["value1"].ToString()
}
}
.....
if(dataSet.Tables.Contains("TableN") {
var dataRowN = dataSet.Tables["TableN"].Select();
if(dataRowN.Length > 0) {
valueN = dataRowN[0]["valueN"].ToString()
}
}
#endregion
}
}
The above snippet is an abstract skeleton of a large legacy project in which there are many methodS() like:
method1()
method2()
.....
methodN()
Almost all of these require almost all valueS:
value1
value2
...
valueN
which are populated using populateValues().
This is how abc is used in other places:
class xyz {
abc a = new abc();
public void doingSomething() {
//Get data from DB and populate to dataSet
a.method1();
a.method5();
....
}
public void doingSomethingElse() {
//Get data from DB and populate to dataSet
a.method1();
return;
}
}
doingSomething() is part of a web service project which is mostly called at the same time from few overlapping-lu running windows service projects.
I'm seeing a danger of possible overwriting of valueS by populateValues() when any of the methodS() are called in parallel.
The structure of dataSet is mostly unpredictable and hence I always need to check the Table1 existence.
The methods will mostly be called in parallel as they're part of a web services project.
How do I save myself from overwriting these large number of values without messing the code in C#?
In other words, how do we make sure that the valueS set after methodN() is not passed to methodN+1() when they're called simultaneously?
The most safe approach would be to copy pasted entire populateValues() body in each methodS() however, this will mess the project a lot.
Declare a class having all Values
Class resultVals
{
string value1 = "", value2 = "", ........... valueN = "";
}
Modify populateValues to return new class resultVals.
public resultVals populateValues(DataSet dataSet) {
resultVals valueS =new resultVals() ;
#region populate valueS so they can be used by methodS
if(dataSet.Tables.Contains("Table1") {
var dataRow1 = dataSet.Tables["Table1"].Select();
if(dataRow1.Length > 0) {
valueS.value1 = dataRow1[0]["value1"].ToString()
}
}
.....
if(dataSet.Tables.Contains("TableN") {
var dataRowN = dataSet.Tables["TableN"].Select();
if(dataRowN.Length > 0) {
valueS.valueN = dataRowN[0]["valueN"].ToString()
}
}
#endregion
}
return resultVals ;
}
Use the returned value (resultVals) in all methods.
public void method1(DataSet dataSet) {
resultVals valueS = populateValues()
and use it for doing something
}
You need to synchronize populateValues
lock(new object())
{
var result = populateValues();
}
However, lock is the simplest one. There are others. ex, you can use Monitor class as well.
Remove all the fields from the abc class.
Remove populate values method.
Create extension method to get value by a number.
Use the extension in place of the valueN field (easily regexp replaced in the code file).
public static string GetValue(this DataSet dataSet, int n)
{
if (dataSet.Tables.Contains("Table" + n)
{
var dataRow = dataSet.Tables["Table" + n].Select();
if (dataRow.Length > 0)
{
return = dataRow[0]["value" + n].ToString()
}
}
return string.Empty;
}
public void method1(DataSet dataSet)
{
var value1 = dataSet.GetValue(1);
}
Better yet, combine this with the Anil's answer and use a struct
public struct Values
{
public string value1;
...
public string valueN;
public static Values Init(DataSet dataSet)
{
// populate values logic here (use the extension from above)
value1 = dataSet.GetValue(1);
...
valueN = dataSet.GetValue(N);
}
}
And then call the methods.
var dataSet = new DataSet();
var values = Values.Init(dataSet);
a.method1(values);
a.method5(values);
public void method1(Values values)
{
// use values.value1 instead of value1 here
}

How do I display and sort a List in C#?

I have a List of "StudentRecords" which contain students and their test scores. For each student, I have their names, age, contact phone number, test scores, and the dates they took a test.
public class StudentRecord
{
public String Name { get; set; }
public int Age { get; set; }
public String PhoneNum { get; set; }
public int TestScore1 { get; set; }
public DateTime TestScore1Date { get; set; }
}
List<StudentRecord> StudentList = new List<StudentRecord>();
dataGridView1.DataSource = StudentList;
I binded my List to a DataGridView control and am able to view the information just great. Now, I want to be able to sort the contents of the List by things like Name first, then scores, then age within the DataGrid control.
I found this:
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.columnheadermouseclick.aspx
which says the default behavior is to order the grid rows based on the clicked column header. However, this does not happen by default when I click. In fact, nothing happens when I click on the column header. Any idea what I might be doing wrong?
Unfortunately, this behavior is not available out-of-the-box with the DataGridView control. In order to use List<T> as the binding source and allow for column click sorting, then you need to handle the ColumnHeaderMouseClick event of the DataGridView, like this:
protected void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
// Get the information about the column clicked
var strColumnName = dataGridView1.Columns[e.ColumnIndex].Name;
SortOrder strSortOrder = getSortOrder(e.ColumnIndex);
// Sort the list
StudentList.Sort(new StudentComparer(strColumnName, strSortOrder));
// Rebind to use sorted list
dataGridView1.DataSource = null;
dataGridView1.DataSource = StudentList;
// Update user interface icon for sort order in column clicked
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder;
}
private SortOrder getSortOrder(int columnIndex)
{
if (dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.None ||
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.Descending)
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
return SortOrder.Ascending;
}
else
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Descending;
return SortOrder.Descending;
}
}
public class StudentComparer : IComparer<StudentRecord>
{
string memberName = String.Empty;
SortOrder sortOrder = SortOrder.None;
public StudentComparer(string strMemberName, SortOrder sortingOrder)
{
memberName = strMemberName;
sortOrder = sortingOrder;
}
public int Compare(StudentRecord student1, StudentRecord student2)
{
int returnValue = 1;
switch (memberName)
{
case "Name" :
if (sortOrder == SortOrder.Ascending)
{
returnValue = student1.Name.CompareTo(student2.Name);
}
else
{
returnValue = student2.Name.CompareTo(student1.Name);
}
break;
case "Age":
if (sortOrder == SortOrder.Ascending)
{
returnValue = student1.Age.CompareTo(student2.Age);
}
else
{
returnValue = student2.Age.CompareTo(student1.Age);
}
break;
case "PhoneNum":
if (sortOrder == SortOrder.Ascending)
{
returnValue = student1.PhoneNum.CompareTo(student2.PhoneNum);
}
else
{
returnValue = student2.PhoneNum.CompareTo(student1.PhoneNum);
}
break;
case "TestScore1":
if (sortOrder == SortOrder.Ascending)
{
returnValue = student1.TestScore1.CompareTo(student2.TestScore1);
}
else
{
returnValue = student2.TestScore1.CompareTo(student1.TestScore1);
}
break;
case "TestScore1Date":
if (sortOrder == SortOrder.Ascending)
{
returnValue = student1.TestScore1Date.CompareTo(student2.TestScore1Date;
}
else
{
returnValue = student2.TestScore1Date.CompareTo(student1.TestScore1Date);
}
break;
default:
if (sortOrder == SortOrder.Ascending)
{
returnValue = Student1.Name.CompareTo(Student2.Name);
}
else
{
returnValue = Student2.Name.CompareTo(Student1.Name);
}
break;
}
return returnValue;
}
}
Note: The default sorting criteria is Name.
You must implement a custom code to datagrid can sort the data. means of that document about default behavior is that when you double click the grid in design mode, VS generate a method to handle this event.
read this : Sort DataGrid
First I think you need to implement that behavior, I doubt it's out of the box.
Second, you could easily sort your objects using LINQ, and have nice groups etc.
Now, if you would like to sort them by different criteria according to clicks, you might need to go with a ListView, and then you would be able to have filters on that, but this is usually a bit longer to do. Here's the MSDN page and at the bottom you have a link to how to sort on header clicked ...

How to check CONTAINS with multiple values

I am trying to find all the zones that contain 2 or more zone members where the search term is a string value. Here is the code I have. In the FindCommmonZones method when I try to cast the result of an Intersect to an ObservableCollection I get a run-time on an invalid cast. The question is, is there a better way to do this? The string array that is the paramter for FindCommonZones() can be any count of strings. StackOverflow had some other similar posts but none really answered my question - it looked like they all pertained more to SQL.
Some code:
public class Zone
{
public List<ZoneMember> MembersList = new List<ZoneMember>();
private string _ZoneName;
public string zoneName{ get{return _ZoneName;} set{_ZoneName=value;} }
public Zone ContainsMember(string member)
{
var contained = this.MembersList.FirstOrDefault(m => m.MemberWWPN.
Contains(member) || m.MemberAlias.Contains(member));
if (contained != null) { return this; }
else { return null; }
}
}
public class ZoneMember
// a zone member is a member of a zone
// zones have ports, WWPNs, aliases or all 3
{
private string _Alias = string.Empty;
public string MemberAlias {get{return _Alias;} set{_Alias = value; } }
private FCPort _Port = null;
public FCPort MemberPort { get { return _Port; } set { _Port = value; } }
private string _WWPN = string.Empty;
public string MemberWWPN { get { return _WWPN; } set { _WWPN = value; } }
private bool _IsLoggedIn;
public bool IsLoggedIn { get { return _IsLoggedIn; } set { _IsLoggedIn = value; } }
private string _FCID;
public string FCID {get{return _FCID;} set{ _FCID=value; } }
}
private ObservableCollection<ZoneResult> FindCommonZones(string[] searchterms)
{
ObservableCollection<ZoneResult> tempcollection =
new ObservableCollection<ZoneResult>();
//find the zones for the first search term
tempcollection = this.FindZones(searchterms[0]);
//now search for the rest of the search terms and compare
//them to existing result
for (int i = 1; i < searchterms.Count(); i++ )
{
// this line gives an exception trying to cast
tempcollection = (ObservableCollection<ZoneResult>)tempcollection.
Intersect(this.FindZones(searchterms[i]));
}
return tempcollection;
}
private ObservableCollection<ZoneResult> FindZones(string searchterm)
// we need to track the vsan where the zone member is found
// so use a foreach to keep track
{
ObservableCollection<ZoneResult> zonecollection = new ObservableCollection<ZoneResult>();
foreach (KeyValuePair<int, Dictionary<int, CiscoVSAN>> fabricpair in this.FabricDictionary)
{
foreach (KeyValuePair<int, CiscoVSAN> vsanpair in fabricpair.Value)
{
var selection = vsanpair.Value.ActiveZoneset.
ZoneList.Select(z => z.ContainsMember(searchterm)).
Where(m => m != null).OrderBy(z => z.zoneName);
if (selection.Count() > 0)
{
foreach (Zone zone in selection)
{
foreach (ZoneMember zm in zone.MembersList)
{
ZoneResult zr = new ZoneResult(zone.zoneName,
zm.MemberWWPN, zm.MemberAlias, vsanpair.Key.ToString());
zonecollection.Add(zr);
}
}
}
}
}
return zonecollection;
}
Intersect is actually Enumerable.Intersect and is returning an IEnumerable<ZoneResult>. This is not castable to an ObservableCollection because it isn't one - it is the enumeration of the intersecting elements in both collections.
You can, however create a new ObservableCollection from the enumeration:
tempcollection = new ObservableCollection<ZoneResult>(tempcollection
.Intersect(this.FindZones(searchterms[i]));
Depending on how many elements you have, how ZoneResult.Equals is implemented, and how many search terms you expect, this implementation may or may not be feasable (FindZones does seem a little overly-complicated with O(n^4) at first glance). If it seems to be a resource hog or bottleneck, it's time to optimize; otherwise I would just leave it alone if it works.
One suggested optimization could be the following (incorporating #Keith's suggestion to change ContainsMember to a bool) - although it is untested, I probably have my SelectManys wrong, and it really largely amounts to the same thing, you hopefully get the idea:
private ObservableCollection<ZoneResult> FindCommonZones(string[] searchterms)
{
var query = this.FabricDictionary.SelectMany(fabricpair =>
fabricpair.Value.SelectMany(vsanpair =>
vsanpair.Value.ActiveZoneSet.ZoneList
.Where(z=>searchterms.Any(term=>z.ContainsMember(term)))
.SelectMany(zone =>
zone.MembersList.Select(zm=>new ZoneResult(zone.zoneName, zm.MemberWWPN, zm.MemberAlias, vsanpair.Key.ToString()))
)
)
.Distinct()
.OrderBy(zr=>zr.zoneName);
return new ObservableCollection<ZoneResult>(query);
}

Categories