Get ListView items that are checked - c#

I have listview with combox=true containg images. Each item is assigned a tag.
I can get tag of focussed item:
string name = this.lstview1.FocusedItem.Tag.ToString();
I can get index of checked item:
list = lstview1.CheckedIndices.Cast<int>().ToList();
How do I get the tag of the checked item?

You can use CheckedItems property instead of CheckedIndices:
var selectedTags = this.listView1.CheckedItems
.Cast<ListViewItem>()
.Select(x => x.Tag);
Anyway, also CheckedIndices can be used, e.g.:
var selectedTags = this.listView1.CheckedIndices
.Cast<int>()
.Select(i => this.listView1.Items[i].Tag);
EDIT:
Little explanation of LINQ Select():
The following code:
var selectedTags = this.listView1.CheckedItems
.Cast<ListViewItem>()
.Select(x => x.Tag);
foreach(var tag in selectedTags)
{
// do some operation using tag
}
is functionally equal to:
foreach(ListViewItem item in this.listView1.CheckedItems)
{
var tag = item.Tag;
// do some operation using tag
}
In this particular example is not so useful, nor shorter in term of code length, but, believe me, in many situations LINQ is really really helpful.

How about
var x = listView1.Items[listView1.CheckedIndices.Cast().ToList().First()].Tag;
?

Related

Ordering Linq list by array elements

I have below code -
var refNosToOrder = new int[9] {1,2,3,4,5,6,7,8,9}
var orderedList = lst.OrderBy(x=>x.RefNo==7)
.ThenBy(y=> refNosToOrder.Contains(y.RefNo)).ToList();
lst is list of class object containing int property - RefNo : i.e. List<SampleClass>
class SampleClass
{
public int RefNo {get;set;}
}
lst contains all the unsorted data of RefNo:
lst = 2,4,6,9,7,5,8,1,3
What I want to do -
First I want to order lst by keeping first element as - 7; then for the rest of the list, it should be ordered as the array refNosToOrder
i.e. Final output I am expecting to be -
7,1,2,3,4,5,6,8,9
With the above code -
var orderedList = lst.OrderBy(x=>x.RefNo==7)
.ThenBy(y=> refNosToOrder.Contains(y.RefNo)).ToList();
It is giving - 2,4,6,9,7,5,8,1,3 i.e. this code is not at all ordering the list.
Contains returns a boolean of whether an element is in a list or not, which won't be very helpful here. Instead, you could sort by the index of that element:
var orderedList =
lst.OrderBy(x => x.RefNo != 7)
.ThenBy(y => Array.IndexOf(refNosToOrder, y.RefNo))
.ToList();
EDIT:
Following up on Jeroen Mostert's comment, this sorting has quadratic complexity. For large refNosToOrder it may be more efficient to first convert the array to a dictionary of orders and then use it for the sorting:
var orderDict =
Enumerable.Range(0, refNosToOrder.Length).ToDictionary(i => refNosToOrder[i]);
var orderedList =
lst.OrderBy(x => x.RefNo != 7).ThenBy(y => orderDict[y.RefNo]).ToList();

Filter a collection column by multiple values

I have a collection and I would like to filter it with one of the column contains multiple values. The filter values are dynamically generated and I dont know how many I will get.
I tried the following without success:
var input = #"was.Name.Contains(""Test"") || was.Name.Contains(""Test2"")";
var test = collection.Where(was => input)).ToList();
Assuming you receive the filter values as a CSV string:
var csvFilters = "Test1, Test2";
// split by ',', remove empty entries,
// trim each filter and store the result in a list
var filters = csvFilters.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.ToList();
// return items in collection whose Name property
// is equal to any of the items in filters
var result = collection.Where(x => filters.Contains(x.Name)).ToList();
This should translate to the following SQL:
SELECT * FROM collection c
WHERE c.Name IN ('Test1', 'Test2')
I guess you want to use LINQ. The question is, how the "filter" values are kept? I'll answer in the way I understand your question.
If input is supposed to be a condition then I'd suggest using Func<Object,bool>. This means, the input would be the condition you're looking for, and if found, it would return true.
Here is a simple example:
IEnumerable <T> FindElements (Func<Object, bool> condition, IEnumerable<T> inputList)
{
List<T> outputList = new List<T>();
foreach(var element in inputList)
{
if(condition != null && condition(element))
outputList.Add(element);
}
return outputList;
}
Then, if you call the function given exemplary parameters:
string input[] = {"Test1","Test2"};
foreach(string s in input)
{
targetList = FindElements(element=>((cast)element).Name.Contains(s), collection);
}
You should get all elements in collection which name has Test1 or Test2. Cast is of course name of the class which element instantiates.

how to filter a MVC SelectList to remove unwanted values

I have a SelectList and I need to filter out when the Text value is emptyOrNull? I'm struggling to get this working. Any ideas? I've tried this
Example code
// My list - this is valid code
SelectList list = model.MySelectList;
// But when I try this I get the following error message?
SelectList test = list.Where(x => x.Text != "");
I receive the following compiler error message
Error
Error convert source .. IEnumerable<SelectListItem> to target type SelectList
UPDATE - I need to filter out values, i.e. I need something like
foreach (var item in list)
{
if (string.IsNullOrEmpty(item.Text))
{
// remove item from list
}
}
// Then list does not include any items with a Value which is null or empty
UPDATE
After making the following change, the code compiles but I get 'Select.Web.Mvc.SelectListItem' in the rendered dropdown.
new SelectList(list.Where(x => x.Text != ""));
Please advise, many thanks,
You can do in two ways,
(i). Getting only the values which are not null or not empty using LINQ
List<SelectListItem> test = list.Where(item => item.Text != null || !(item.Text.Equals(string.Empty))).ToList();
(ii).Second way is to find the values and remove from the original
List<SelectListItem> filedNullOrEmpty = list.Where(item => item.Text == null || item.Text.Equals(string.Empty)).ToList();
foreach (Select selobj in filedNullOrEmpty)
{
list.Remove(selobj);
}
It is happened because .Where() returns IEnumerable. You should convert to SeletList type.
One of option is .Where(x => x.Text != "").Select(new SelectListItem(){Text = x.Text, Value = x.Value});
The SelectList constructor takes an IEnumerable so all you need to do is pass the LINQ query to the constructor like so
var query = from c in source
where c.Key != ""
select c;
var customerList = new SelectList(query, "DataTextField", "DataValueField");
Wish I could help you.
Enumerable.Where returns IEnumerable<T>, not SelectList - try using this constructor:
SelectList test = new SelectList(list.Where(x => !String.IsNullOrEmpty(x.Text)));

How to get first object out from List<Object> using Linq

I have below code in c# 4.0.
//Dictionary object with Key as string and Value as List of Component type object
Dictionary<String, List<Component>> dic = new Dictionary<String, List<Component>>();
//Here I am trying to do the loping for List<Component>
foreach (List<Component> lstComp in dic.Values.ToList())
{
// Below I am trying to get first component from the lstComp object.
// Can we achieve same thing using LINQ?
// Which one will give more performance as well as good object handling?
Component depCountry = lstComp[0].ComponentValue("Dep");
}
Try:
var firstElement = lstComp.First();
You can also use FirstOrDefault() just in case lstComp does not contain any items.
http://msdn.microsoft.com/en-gb/library/bb340482(v=vs.100).aspx
Edit:
To get the Component Value:
var firstElement = lstComp.First().ComponentValue("Dep");
This would assume there is an element in lstComp. An alternative and safer way would be...
var firstOrDefault = lstComp.FirstOrDefault();
if (firstOrDefault != null)
{
var firstComponentValue = firstOrDefault.ComponentValue("Dep");
}
[0] or .First() will give you the same performance whatever happens.
But your Dictionary could contains IEnumerable<Component> instead of List<Component>, and then you cant use the [] operator. That is where the difference is huge.
So for your example, it doesn't really matters, but for this code, you have no choice to use First():
var dic = new Dictionary<String, IEnumerable<Component>>();
foreach (var components in dic.Values)
{
// you can't use [0] because components is an IEnumerable<Component>
var firstComponent = components.First(); // be aware that it will throw an exception if components is empty.
var depCountry = firstComponent.ComponentValue("Dep");
}
You also can use this:
var firstOrDefault = lstComp.FirstOrDefault();
if(firstOrDefault != null)
{
//doSmth
}
for the linq expression you can use like this :
List<int> list = new List<int>() {1,2,3 };
var result = (from l in list
select l).FirstOrDefault();
for the lambda expression you can use like this
List list = new List() { 1, 2, 3 };
int x = list.FirstOrDefault();
You can do
Component depCountry = lstComp
.Select(x => x.ComponentValue("Dep"))
.FirstOrDefault();
Alternatively if you are wanting this for the entire dictionary of values, you can even tie it back to the key
var newDictionary = dic.Select(x => new
{
Key = x.Key,
Value = x.Value.Select( y =>
{
depCountry = y.ComponentValue("Dep")
}).FirstOrDefault()
}
.Where(x => x.Value != null)
.ToDictionary(x => x.Key, x => x.Value());
This will give you a new dictionary. You can access the values
var myTest = newDictionary[key1].depCountry
Try this to get all the list at first, then your desired element (say the First in your case):
var desiredElementCompoundValueList = new List<YourType>();
dic.Values.ToList().ForEach( elem =>
{
desiredElementCompoundValue.Add(elem.ComponentValue("Dep"));
});
var x = desiredElementCompoundValueList.FirstOrDefault();
To get directly the first element value without a lot of foreach iteration and variable assignment:
var desiredCompoundValue = dic.Values.ToList().Select( elem => elem.CompoundValue("Dep")).FirstOrDefault();
See the difference between the two approaches: in the first one you get the list through a ForEach, then your element. In the second you can get your value in a straight way.
Same result, different computation ;)
There are a bunch of such methods:
.First .FirstOrDefault .Single .SingleOrDefault
Choose which suits you best.
var firstObjectsOfValues = (from d in dic select d.Value[0].ComponentValue("Dep"));
I would to it like this:
//Dictionary object with Key as string and Value as List of Component type object
Dictionary<String, List<Component>> dic = new Dictionary<String, List<Component>>();
//from each element of the dictionary select first component if any
IEnumerable<Component> components = dic.Where(kvp => kvp.Value.Any()).Select(kvp => (kvp.Value.First() as Component).ComponentValue("Dep"));
but only if it is sure that list contains only objects of Component class or children

c# More elegant way to assign array to a list?

I have this:
// Load changelog types
ChangeLogType[] Types = ChangeLogFunctions.GetAllChangelogTypes();
foreach(ChangeLogType Rec in Types){
ListItem N = new ListItem();
N.Text = Rec.Type;
N.Value = Rec.ID.ToString();
LstChangeLogType.Items.Add(N);
}
It calls a function that returns an array of ChangeLogTypes, and then adds each one into a list control. Is there a more elegant way of doing this? I feel I'm repeating code each time I do this or something similar.
Yup, LINQ to Objects is your friend:
var changeLogTypes = ChangeLogFunctions.GetAllChangelogTypes()
.Select(x => new ListItem {
Text = x.Type,
Value = x.ID.ToString() })
.ToList();
The Select part is projecting each ChangeLogType to a ListItem, and ToList() converts the resulting sequence into a List<ListItem>.
This is assuming you really wanted a new list with all these entries. If you need to add the results to an existing list, you'd do that without the ToList call, but calling AddRange on an existing list with the result of the Select call.
It's well worth learning more about LINQ in general and LINQ to Objects in particular - it can make all kinds of things like this much simpler.
var range = Types.Select(rec =>
new ListItem { Text = rec.Type, Value = rec.ID.ToString() });
LstChangeLogType.AddRange(range);
Linq?
LstChangeLogType.Items = Types.Select(x => new ListItem()
{ Text = x.Type, Value = x.ID.ToString() }).ToList();
using System.Linq;
var items = Types
.Select (rec => ListItem
{
Text = Rec.Type;
Value = Rec.ID.ToString();
}
LstChangeLogType.Items.AddRange(items);
Using some LINQ extension methods:
LstChangeLogType.AddItems.AddRange(
Types.Select(t =>
new ListItem() { Text = t.Type, Value = t.ID.ToString() }).ToArray());

Categories