foreach statement cannot operate on variables of type 'Diary_Entry' - asp.net

Passing in a list of dates 'DiaryEntry' through the foreach loop. every date that it records will be highlighted on the calendar....
foreach (DateTime d in DiaryEntry)
{
Calendar1.SelectedDates.Add(d);//CALENDAR1 being the ID of the calendar on the aspx page
}
ERROR: foreach statement cannot operate on variables of type 'Diary_Entry' because 'Diary_Entry' does not contain a public defination for 'GetEnumerator'
Anyone have any idea how I can resolve this?
Thanks

Is Diary_Entry meant to be a list of some kind? Is it based on a collection class, something that implements System.Collections.IEnumerable or System.Collections.Generic.IEnumerable? If not, if it just has a couple of properties that represent dates, you can't use foreach with it. You'd have to process each property separately.
Calendar1.SelectedDates.Add(Diary_Entry.Date1);
Calendar1.SelectedDates.Add(Diary_Entry.Date2);
// etc.
If it has two dates, representing a start and end date, and you want to iterate through the range, you wouldn't be able to use foreach with it, but you could still use for:
for(DateTime d = Diary_Entry.StartDate;d<=Diary_Entry.EndDate;d=d.AddDays(1))
{
Calendar1.SelectedDates.Add(d);
}

Your DiaryEntry object needs to implement IEnumerable or IEnumerable<T>.
From msdn:
The foreach statement repeats a group of embedded statements for each
element in an array or an object collection that implements the
System.Collections.IEnumerable or
System.Collections.Generic.IEnumerable<T> interface.
I suspect you mean to have an array or some other collection of those objects. In that case you could iterate over the collection with a foreach. Another possibility is that DiaryEntry has a collection property on it, and you mean to iterate over that... like the following maybe?
foreach(DateTime date in DiaryEntry.Dates)
{
...
}

Related

In a C# TBB: how to split a multi SingleLineTextField into seperate strings

I have a plain textfield in Tridion that can have multiple values. The itemtype is a SingleLineTextField.
In the TBB code I have the following (removed the non-essential parts):
ItemFields itemFields = new ItemFields(folder.Metadata, folder.MetadataSchema);
foreach (ItemField itemField in itemFields)
{
string itemFieldValue = string.Empty;
switch (Utilities.GetFieldType(itemField))
{
case FieldType.SingleLineTextField:
itemFieldValue = itemField.ToString();
break;
}
}
Now the result in case of two entries is just two strings with a character line break in it.
String A
String B
The method used is a generic one, which also works on other fields, so I was looking for some way to find out if a SingleLineTextField has more values in it.
You can cast the field to a SingleLineTextField type, then iterate through the Values collection, something along these lines:
SingleLineTextField field = (SingleLineTextField)itemField;
foreach(string value in field.Values)
{
// do something with value
}
// or if all you want is the count of values
int i = field.Values.Count;
Firstly, I would advise against relying on the ToString() method on objects unless it is specifically documented. In this case it works with the abstract class ItemField, but this may not always be the case.
The TOM.Net API only defines Definition and Name properties for ItemField, so you need to cast your ItemField object to something more specific.
the TextField abstract class, which SingleLineTextField inherits from, defines a ToString() method, but also Value and Values properties, which are much better suited to what you're trying to do. Looking at the documentation, we can see that Values will give us an IList<String> of the values, even if your field is not multi-valued. Perfect!
So, to answer your question, "I was looking for some way to find out if a SingleLineTextField has more values in it", you need to cast your ItemField as a TextField and check the number of Values it provides, thus:
TextField textField = (TextField)itemField;
// If you need to deal with multi-valued fields separately
if (textField.Values.Count > 1)
{
//Logic to deal with multiple values goes here
}
else
{
//Logic to deal with single valued goes here
}
// Much better... If you can deal with any number of values in a generic fashion
foreach (string value in textField.Values)
{
// Generic code goes here
}

Flex List limit number of elements

Is it possible to define a property to limit the number of elements which will appear in a mx:List ? I've read about setting the property rowCount, but I don't see any effect.
Can a filter be applied to accomplish this? My intention was to avoid removing the items from the list/array collection, but simply "hide" them. Can this be done?
You can "hide" items from display in a List-based class, without modifying your underlying source data, by using a Collection class, such as an ArrayCollection, and filtering the data.
Read these docs on Collection filtering.
To quote:
You use a filter function to limit the data view in the collection to
a subset of the source data object. The function must take a single
Object parameter, which corresponds to a collection item, and must
return a Boolean value specifying whether to include the item in the
view. As with sorting, when you specify or change the filter function,
you must call the refresh() method on the collection to show the
filtered results. To limit a collection view of an array of strings to
contain only strings starting with M, for example, use the following
filter function:
public function stateFilterFunc(item:Object):Boolean
{
return item >= "M" && item < "N";
}
A different option is to use a new arraycollection and get your limited items from your big arraycollection :
//get first 10 elements
myArrayCollection = new ArrayCollection( myBigArrayCollection.toArray().slice(0,9) );
if you want to work with pagers, you could hold a counter where you keep track of what page the user is on, and get the next elements from you big array collection. example:
//this is just a (very) simple example
//page = integer (counter) for knowing which page the user is on
page = 0;
page_low = page*10;
page_high = page_low + 9;
myArrayCollection = new ArrayCollection( myBigArrayCollection.toArray().slice(page_low,page_high) );
(still using a filter is a more elegant solution)

What's the best way to use hamcrest-AS3 to test for membership in an IList?

I'm using Flex 3.3, with hamcrest-as3 used to test for item membership in a list as part of my unit tests:
var myList: IList = new ArrayCollection(['a', 'b', 'c']).list;
assertThat(myList, hasItems('a', 'b', 'c'));
The problem is that apparently the IList class doesn't support for each iteration; for example, with the above list, this will not trace anything:
for each (var i: * in myList) { trace (i); }
However, tracing either an Array or an ArrayCollection containing the same data will work just fine.
What I want to do is (without having to tear apart my existing IList-based interface) be able to treat an IList like an Array or an ArrayCollection for the purposes of testing, because that's what hamcrest does:
override public function matches(collection:Object):Boolean
{
for each (var item:Object in collection)
{
if (_elementMatcher.matches(item))
{
return true;
}
}
return false;
}
Is this simply doomed to failure? As a side note, why would the IList interface not be amenable to iteration this way? That just seems wrong.
You will have to create a custom Matcher that's able to iterate over an IList. More specifically, extend and override the matches method of IsArrayContainingMatcher that you reference above (and you'll probably want to create IList specific versions of hasItem and hasItems as well). A bit of a pain, but perhaps it's worth it to you.
Longer term, you could file an issue with hamcrest-as3 (or fork) to have array iteration abstracted using the Iterator pattern. The right Iterator could then be chosen automatically for the common types (Proxy-subclasses, IList) with perhaps an optional parameter to supply a custom Iterator.
For the main issue: Instead of passing the ArrayCollection.list to assertThat(), pass the ArrayCollection itself. ArrayCollection implements IList and is iterable with for each.
var myList:IList = new ArrayCollection(['a', 'b', 'c']);
assertThat(myList, hasItems('a', 'b', 'c'));
In answer to part two: ArrayCollection.list is an instance of ArrayList which does not extend Proxy and does not implement the required methods in order to iterate with for each. ArrayCollection extends ListCollectionView which does extends Proxy and implements the required methods.
HTH.
I find myself coming back to this every once in a while. Rather than writing new Matchers, I find that the easiest solution is always to just call toArray() on the IList and match against the resulting array.

Flex Dictionary Sorting

I have the following dictionary in flex, and i d like to sort it by value. Couldn't find any resource.
'1'=>2, '0' =>1, '3'=>4 ..
Any ideas ? How can i sort this by value ?
I searched around for a similar solution, except that I needed to sort the dictionary map and return a sorted collection relating key value pairs. After failing to find a published solution I put together the approach below. This method takes a dictionary as input, creates an array maintaining the association then sorts the resultant array using array.sortOn() and returns the sorted results back as an array. "key" and "value" fields in the array in the example below are used for clarity, but any field name could be used.
This example assumes a string object as a key and a numeric object as a value, though of course any object type could be used, and field parameters adjusted.
The approach below could also be used for sorting by key instead of value by using "key" as the sort field for the sortOn method, and you could use different sort options than the descending numeric sort I used here( AS3 SortOn() documentation) Code below is intentionally non-generic to simplify it for example purposes.
public static function sortDictionaryByValue(d:Dictionary):Array
{
var a:Array = new Array();
for (var dictionaryKey:Object in d)
{
a.push({key:dictionaryKey,value:d[dictionaryKey]});
}
a.sortOn("value",[Array.NUMERIC|Array.DESCENDING]);
return a;
}
Probably not the best way to do it but it works:
var a:Array = new Array();
for each (var v:Number in dict)
{
a.push(v);
}
a.sort();

How do I find the length of an associative array in ActionScript 3.0?

Is there a simple way to retrieve the length of an associative array (implemented as an Object) in ActionScript 3.0?
I understand that there are two primary ways of creating associative arrays in AS3:
Use a Dictionary object; especially handy when the key does not need to be a string
Use an Object, and simply create properties for each desired element. The property name is the key, and the value is, well, the value.
My application uses approach #2 (using the Object class to represent associative arrays).
I am hoping there is something more native than my for loop, which manually counts up all the elements.
You have to count them in a for loop as you do. Of course, you could make a class and stick the for loop in that class.
For some great implmentations of Collections in AS3, check these guys.
Edit 2013 Not surprisingly, links do break after time. Try this new one: http://www.grindheadgames.com/get-the-length-of-an-object.
Doing a few tests on this has actually surprised me. Here's normal use of an Array:
var things:Array = [];
things.push("hi!");
trace(things.length);
// traces 1
trace(things);
// traces hi!
Here's if we set a value to a string:
var things:Array = [];
things["thing"] = "hi!";
trace(things.length);
// traces 0
trace(things);
// traces an empty string
trace(things["thing"]);
// traces hi!
Basically if you add things using strings you're setting properties rather than actually adding to the array. Makes me wonder why Array is dynamic in this way.
So... yeah count the items with a for ... in loop!
I think you're stuck with counting them "manually".
An option would be to wrap the whole thing in a class and keep a separate variable that you update as you add/remove.
var count:int;
var key:String;
for (key in myObject)
{
count++;
}
trace ("myObject has this many keys in it: " + count);
or, alternatively, the for-each syntax (I haven't tested to see which is faster)
for each (var o:* in myObject)
{
count++;
}

Resources