deserialization error : "<book xmlns=''> was not expected." DeSerialize from xml string - asp.net

I am having problem deserializing xml to multiple class objects. when i try yo deserialize
i am getting " was not expected."
Here is my calling code
StringReader strReader = new StringReader(xml);
XmlTextReader reader = new XmlTextReader(strReader);
reader.ReadToDescendant("book");
var temp = DeserializeFromXml<book>(reader.ReadOuterXml());
public static T DeserializeFromXml<T>(string xml)
{
T result;
XmlRootAttribute xRoot = new XmlRootAttribute();
XmlSerializer ser = new XmlSerializer(typeof(T));
using (TextReader tr = new StringReader(xml))
{
result = (T)ser.Deserialize(tr);
}
return result;
}
xml is string message
<?xml version="1.0" encoding="UTF-8"?><books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<book genre="novel">
<title>The Handmaid's Tale</title>
<price>19.95</price>
<ISBN>1-861003-78</ISBN>
<style>hardcover</style>
</book>
<library genre="novel">
<name>Oxford</name>
<location>london</location>
<ISBN>1-8888888-88</ISBN>
<address>12th main, chesmedia</address>
</library>
When i try to execute this code i get this inner exception " was not expected."
Here is my class code
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.233")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/SampleBooks.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/SampleBooks.xsd", IsNullable = false)]
public partial class books
{
private book bookField;
private library libraryField;
private static System.Xml.Serialization.XmlSerializer serializer;
public books()
{
this.libraryField = new library();
this.bookField = new book();
}
[System.Xml.Serialization.XmlElementAttribute(Order = 0)]
public book book
{
get
{
return this.bookField;
}
set
{
this.bookField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute(Order = 1)]
public library library
{
get
{
return this.libraryField;
}
set
{
this.libraryField = value;
}
}
private static System.Xml.Serialization.XmlSerializer Serializer
{
get
{
if ((serializer == null))
{
serializer = new System.Xml.Serialization.XmlSerializer(typeof(books));
}
return serializer;
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.233")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/SampleBooks.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/SampleBooks.xsd", IsNullable = false)]
public partial class book
{
private title titleField;
private decimal priceField;
private ISBN iSBNField;
private style styleField;
private bookGenre genreField;
private static System.Xml.Serialization.XmlSerializer serializer;
[System.Xml.Serialization.XmlElementAttribute(Order = 0)]
public title title
{
get
{
return this.titleField;
}
set
{
this.titleField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute(Order = 1)]
public decimal price
{
get
{
return this.priceField;
}
set
{
this.priceField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute(Order = 2)]
public ISBN ISBN
{
get
{
return this.iSBNField;
}
set
{
this.iSBNField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute(Order = 3)]
public style style
{
get
{
return this.styleField;
}
set
{
this.styleField = value;
}
}
[System.Xml.Serialization.XmlAttributeAttribute()]
public bookGenre genre
{
get
{
return this.genreField;
}
set
{
this.genreField = value;
}
}
private static System.Xml.Serialization.XmlSerializer Serializer
{
get
{
if ((serializer == null))
{
serializer = new System.Xml.Serialization.XmlSerializer(typeof(book));
}
return serializer;
}
}
}

Simply take off the Namespace = from the attribute of your Book class.
So your code will be like
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.233")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/SampleBooks.xsd")]
[System.Xml.Serialization.XmlRootAttribute(IsNullable = false)]
public partial class book

Related

autocomplete for TKCustomMap from CustomList

I took from a GitHub TkCustomMap project TK.CustomMap, and I want to call my custom service, to fill my custom list, and on ItemSelected event, from autocomplete searchBar to MapCenter it with Coordinates from my list model.
I've tried and I stopped at binding and on ItemSelect event.
Here is my MapPage:
using Xamarin.Forms;
using Xamarin.Forms.Maps;
namespace TK.CustomMap.Sample
{
public partial class SamplePage : ContentPage
{
public SamplePage()
{
//InitializeComponent();
this.CreateView();
this.BindingContext = new SampleViewModel();
}
private async void CreateView()
{
var autoComplete = new PlacesAutoComplete { ApiToUse = PlacesAutoComplete.PlacesApi.CustomList };
autoComplete.SetBinding(PlacesAutoComplete.MapSelectedCommandProperty, "MapCenter");
var newYork = new Position(40.7142700, -74.0059700);
var mapView = new TKCustomMap(MapSpan.FromCenterAndRadius(newYork, Distance.FromKilometers(2)));
mapView.IsShowingUser = true;
mapView.SetBinding(TKCustomMap.CustomPinsProperty, "Pins");
mapView.SetBinding(TKCustomMap.MapClickedCommandProperty, "MapClickedCommand");
mapView.SetBinding(TKCustomMap.MapLongPressCommandProperty, "MapLongPressCommand");
mapView.SetBinding(TKCustomMap.MapCenterProperty, "MapCenter");
mapView.SetBinding(TKCustomMap.PinSelectedCommandProperty, "PinSelectedCommand");
mapView.SetBinding(TKCustomMap.SelectedPinProperty, "SelectedPin");
mapView.SetBinding(TKCustomMap.RoutesProperty, "Routes");
mapView.SetBinding(TKCustomMap.PinDragEndCommandProperty, "DragEndCommand");
mapView.SetBinding(TKCustomMap.CirclesProperty, "Circles");
mapView.SetBinding(TKCustomMap.CalloutClickedCommandProperty, "CalloutClickedCommand");
mapView.SetBinding(TKCustomMap.PolylinesProperty, "Lines");
mapView.SetBinding(TKCustomMap.PolygonsProperty, "Polygons");
mapView.SetBinding(TKCustomMap.MapRegionProperty, "MapRegion");
mapView.SetBinding(TKCustomMap.RouteClickedCommandProperty, "RouteClickedCommand");
mapView.SetBinding(TKCustomMap.RouteCalculationFinishedCommandProperty, "RouteCalculationFinishedCommand");
mapView.SetBinding(TKCustomMap.TilesUrlOptionsProperty, "TilesUrlOptions");
mapView.SetBinding(TKCustomMap.MapFunctionsProperty, "MapFunctions");
mapView.IsRegionChangeAnimated = true;
autoComplete.SetBinding(PlacesAutoComplete.BoundsProperty, "MapRegion");
RelativeLayout _baseLayout = new RelativeLayout();
_baseLayout.Children.Add(
mapView,
Constraint.RelativeToView(autoComplete, (r, v) => v.X),
Constraint.RelativeToView(autoComplete, (r, v) => autoComplete.HeightOfSearchBar),
heightConstraint: Constraint.RelativeToParent((r) => r.Height - autoComplete.HeightOfSearchBar),
widthConstraint: Constraint.RelativeToView(autoComplete, (r, v) => v.Width));
_baseLayout.Children.Add(
autoComplete,
Constraint.Constant(0),
Constraint.Constant(0));
Content = _baseLayout;
}
}
}
Here is my PlacesAutoComplete class:
using System;
using System.Collections.Generic;
using System.Linq;
using TK.CustomMap.Api;
using TK.CustomMap.Api.Google;
using TK.CustomMap.Api.OSM;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using static TK.CustomMap.Sample.SearchBarModel;
namespace TK.CustomMap.Sample
{
public class SearchBarModel : IPlaceResult
{
public string Subtitle { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class PlacesAutoComplete : RelativeLayout
{
public static BindableProperty BoundsProperty = BindableProperty.Create<PlacesAutoComplete, MapSpan>(
p => p.Bounds,
default(MapSpan));
// TODO: SUMMARIES
public enum PlacesApi
{
//Google,
//Osm,
//Native,
//THIS IS MY LIST!
CustomList
}
private readonly bool _useSearchBar;
private bool _textChangeItemSelected;
private SearchBar _searchBar;
private Entry _entry;
private ListView _autoCompleteListView;
private IEnumerable<IPlaceResult> _predictions;
public PlacesApi ApiToUse { get; set; }
public static readonly BindableProperty MapSelectedCommandProperty =
BindableProperty.Create<PlacesAutoComplete, Command<Position>>(
p => p.SetMap, null);
public List<SearchBarModel> myList = new List<SearchBarModel>();
public Command<Position> SetMap
{
get { return (Command<Position>)this.GetValue(MapSelectedCommandProperty); }
set { this.SetValue(MapSelectedCommandProperty, value); }
}
public double HeightOfSearchBar
{
get
{
return this._useSearchBar ? this._searchBar.Height : this._entry.Height;
}
}
private string SearchText
{
get
{
return this._useSearchBar ? this._searchBar.Text : this._entry.Text;
}
set
{
if (this._useSearchBar)
this._searchBar.Text = value;
else
this._entry.Text = value;
}
}
public new MapSpan Bounds
{
get { return (MapSpan)this.GetValue(BoundsProperty); }
set { this.SetValue(BoundsProperty, value); }
}
public PlacesAutoComplete(bool useSearchBar)
{
this._useSearchBar = useSearchBar;
this.Init();
}
public string Placeholder
{
get { return this._useSearchBar ? this._searchBar.Placeholder : this._entry.Placeholder; }
set
{
if (this._useSearchBar)
this._searchBar.Placeholder = value;
else
this._entry.Placeholder = value;
}
}
public PlacesAutoComplete()
{
this._useSearchBar = true;
this.Init();
}
private void Init()
{
OsmNominatim.Instance.CountryCodes.Add("de");
this._autoCompleteListView = new ListView
{
IsVisible = false,
RowHeight = 40,
HeightRequest = 0,
BackgroundColor = Color.White
};
this._autoCompleteListView.ItemTemplate = new DataTemplate(typeof(MapSearchCell));
View searchView;
if (this._useSearchBar)
{
this._searchBar = new SearchBar
{
Placeholder = "Search for address..."
};
this._searchBar.TextChanged += SearchTextChanged;
this._searchBar.SearchButtonPressed += SearchButtonPressed;
searchView = this._searchBar;
}
else
{
this._entry = new Entry
{
Placeholder = "Sarch for address"
};
this._entry.TextChanged += SearchTextChanged;
searchView = this._entry;
}
this.Children.Add(searchView,
Constraint.Constant(0),
Constraint.Constant(0),
widthConstraint: Constraint.RelativeToParent(l => l.Width));
this.Children.Add(
this._autoCompleteListView,
Constraint.Constant(0),
Constraint.RelativeToView(searchView, (r, v) => v.Y + v.Height));
this._autoCompleteListView.ItemSelected += ItemSelected;
this._textChangeItemSelected = false;
}
private void SearchButtonPressed(object sender, EventArgs e)
{
if (this._predictions != null && this._predictions.Any())
this.HandleItemSelected(this._predictions.First());
else
this.Reset();
}
private void SearchTextChanged(object sender, TextChangedEventArgs e)
{
if (this._textChangeItemSelected)
{
this._textChangeItemSelected = false;
return;
}
this.SearchPlaces();
}
private async void SearchPlaces()
{
try
{
if (string.IsNullOrEmpty(this.SearchText))
{
this._autoCompleteListView.ItemsSource = null;
this._autoCompleteListView.IsVisible = false;
this._autoCompleteListView.HeightRequest = 0;
return;
}
IEnumerable<IPlaceResult> result = null;
if (this.ApiToUse == PlacesApi.CustomList)
{
myList.Add(new SearchBarModel
{
Name = "Test1",
Description = "On item select, show me on map!",
Longitude = 20.4680701,
Latitude = 44.8152658
});
myList.Add(new SearchBarModel
{
Name = "Test2",
Description = "On item select, show me on map!",
Longitude = 20.4233035,
Latitude = 44.805651,
});
myList.Add(new SearchBarModel
{
Name = "Test3",
Description = "On item select, show me on map!",
Longitude = 20.456054,
Latitude = 44.8839925
});
myList.Add(new SearchBarModel
{
Name = "Test4",
Description = "On item select, show me on map!",
Longitude = 20.4328035,
Latitude = 44.8071928,
});
result = myList.OfType<IPlaceResult>().ToList<IPlaceResult>();
}
else
{
result = await OsmNominatim.Instance.GetPredictions(this.SearchText);
}
if (result != null && result.Any())
{
this._predictions = result;
this._autoCompleteListView.HeightRequest = result.Count() * 40;
this._autoCompleteListView.IsVisible = true;
this._autoCompleteListView.ItemsSource = this._predictions;
}
else
{
this._autoCompleteListView.HeightRequest = 0;
this._autoCompleteListView.IsVisible = false;
}
}
catch (Exception x)
{
// TODO
}
}
//From here my code partially works
private void ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null) return;
var prediction = (IPlaceResult)e.SelectedItem;
this.HandleItemSelected(prediction);
}
private void HandleItemSelected(IPlaceResult prediction)
{
if (this.SetMap != null && this.SetMap.CanExecute(this))
{
this.SetMap.Execute(prediction);
}
this._textChangeItemSelected = true;
this.SearchText = prediction.Description;
this._autoCompleteListView.SelectedItem = null;
this.Reset();
}
private void Reset()
{
this._autoCompleteListView.ItemsSource = null;
this._autoCompleteListView.IsVisible = false;
this._autoCompleteListView.HeightRequest = 0;
if (this._useSearchBar)
this._searchBar.Unfocus();
else
this._entry.Unfocus();
}
}
}

Abstract property with JsonIgnore is being serialized (Json.NET)

I have the following setup:
public abstract class A
{
[JsonIgnore]
public abstract Type Foo { get; }
}
public abstract class B : A
{
public override Type Foo { get { return typeof(D); } }
}
public class C : B
{
}
public abstract class D
{
}
My problem is that when I serialize an instance of C via the following:
JsonConvert.SerializeObject(instanceOfC, serializationSettings));
The resulting JSON includes an entry for property Foo. Is this the expected result?
My serializationSettings are as follows:
JsonSerializerSettings _serializationSettings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
TypeNameHandling = TypeNameHandling.All,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
};
Edit: Using Json.NET 6.0.0 and .NET 4.5.
I've had the same problem and I've solved it by specifying a "ContractResolver" property of JsonSerializerSettings like this (initialize all necessary properties for you ):
var settings = new JsonSerializerSettings
{
Formatting = Formatting.None,
ContractResolver = new PublicNotInternalPropertiesCamelCaseContractResolver()
};
And here is my PublicNotInternalPropertiesCamelCaseContractResolver:
public class PublicNotInternalPropertiesCamelCaseContractResolver : CamelCasePropertyNamesContractResolver
{
#region Overrides of DefaultContractResolver
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var members = base
.GetSerializableMembers(objectType)
.Where(m => m.GetCustomAttribute<InternalAttribute>() == null)
.ToList();
return members;
}
#endregion
}
I've had to create an attribute "InternalAttribute", because this solution does not work with JsonIgnoreAttribute for some reasons:
public class InternalAttribute : Attribute
{
}
And I use it like this:
public abstract class RavenDbEntity
{
private string _dbKey;
[Internal]
public string DbKey
{
get { return _dbKey; }
set
{
_dbKey = value;
Id = int.Parse(value.Split('/')[1]);
}
}
public int Id { get; set; }
}
So the output JSON will be without DbKey property

Dynamically attach entry to context

I am using .Net 4.5 and Entity Framework 6 to create a REST Web API.
In my Update methods I need to attach the object recieved in the web api, back to the dbcontext. I have achieved this using the code below. What I want to do now, is to make this code reusable so that I can call AttachToContext for any object in the model.
I understand that I have to use generic type T and TEntity, but I cannot find any suitable examples.
//Repository.cs
public void UpdateOrderItem(OrderItem orderItem)
{
try
{
AttachToContext(orderItem);
_context.SaveChanges();
}
catch (Exception e)
{
}
}
private void AttachToContext(OrderItem orderItem)
{
var entry = _context.Entry<OrderItem>(orderItem);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity(orderItem.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, orderItem);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private OrderItem FindExistingEntity(int id)
{
var set = _context.Set<OrderItem>();
return set.Find(id);
}
private void UpdateEntityValues(OrderItem existing, OrderItem updated)
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
private bool EntityExists(object entity)
{
return entity != null;
}
Your AttachToContext has dependency to primary key property, orderItem.Id, to change it into dynamic, you can introduce an interface and implement to all entities you have or just passing the id as parameters.
Interface
public interface IEntity
{
public int Id { get; set; }
}
public class OrderItem : IEntity
{
// body
}
Then modify the AttachToContext as follow.
private void AttachToContext<T>(T entity) where T : class, IEntity
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(entity.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(int id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem);.
Passing The Keys
private void AttachToContext<T>(T entity, params object[] id) where T : class
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(object[] id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem, orderItem.Id);.
Another alternative would be using object set to get the primary key properties, then using reflection to get the value. To get the primary key properties has been explained in this post.

Steps to map classes using ValueInjector

Quickly getting to the problem the mapping does not occur for the following code. Could someone explain why? or what i should do for the mapping to occur?
var parent = new Parent();
parent.ChildOne.Add(new ChildOne() { Name = "Child One" });
parent.ChildTwo.Add(new ChildTwo() { Name = "Child Two" });
AnotherParent anotherParent = new AnotherParent();
anotherParent.InjectFrom<LoopValueInjection>(parent);
Required Class are below
Anothher child one
public class AnotherChildOne
{
public string Name { get; set; }
}
Another child two
public class AnotherChildTwo
{
public string Name { get; set; }
}
Another Parent
public class AnotherParent
{
public ICollection<AnotherChildOne> ChildOne { get; set; }
public ICollection<AnotherChildTwo> ChildTwo { get; set; }
public AnotherParent()
{
ChildOne = new Collection<AnotherChildOne>();
ChildTwo = new Collection<AnotherChildTwo>();
}
}
Child Two
public class ChildTwo
{
public string Name { get; set; }
}
Child One
public class ChildOne
{
public string Name { get; set; }
}
Parent
public class Parent
{
public ICollection<ChildOne> ChildOne { get; set; }
public ICollection<ChildTwo> ChildTwo { get; set; }
public Parent()
{
ChildOne = new Collection<ChildOne>();
ChildTwo = new Collection<ChildTwo>();
}
}
I believe by default Value Injector will only inject the properties with the same name of the same type. You can get around this using a tweak to the CloneInjection sample from the Value Injector documentation as described here with this code:
public class CloneInjection : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name && c.SourceProp.Value != null;
}
protected override object SetValue(ConventionInfo c)
{
//for value types and string just return the value as is
if (c.SourceProp.Type.IsValueType || c.SourceProp.Type == typeof(string)
|| c.TargetProp.Type.IsValueType || c.TargetProp.Type == typeof(string))
return c.SourceProp.Value;
//handle arrays
if (c.SourceProp.Type.IsArray)
{
var arr = c.SourceProp.Value as Array;
var clone = Activator.CreateInstance(c.TargetProp.Type, arr.Length) as Array;
for (int index = 0; index < arr.Length; index++)
{
var a = arr.GetValue(index);
if (a.GetType().IsValueType || a.GetType() == typeof(string)) continue;
clone.SetValue(Activator.CreateInstance(c.TargetProp.Type.GetElementType()).InjectFrom<CloneInjection>(a), index);
}
return clone;
}
if (c.SourceProp.Type.IsGenericType)
{
//handle IEnumerable<> also ICollection<> IList<> List<>
if (c.SourceProp.Type.GetGenericTypeDefinition().GetInterfaces().Contains(typeof(IEnumerable)))
{
var t = c.TargetProp.Type.GetGenericArguments()[0];
if (t.IsValueType || t == typeof(string)) return c.SourceProp.Value;
var tlist = typeof(List<>).MakeGenericType(t);
var list = Activator.CreateInstance(tlist);
var addMethod = tlist.GetMethod("Add");
foreach (var o in c.SourceProp.Value as IEnumerable)
{
var e = Activator.CreateInstance(t).InjectFrom<CloneInjection>(o);
addMethod.Invoke(list, new[] { e }); // in 4.0 you can use dynamic and just do list.Add(e);
}
return list;
}
//unhandled generic type, you could also return null or throw
return c.SourceProp.Value;
}
//for simple object types create a new instace and apply the clone injection on it
return Activator.CreateInstance(c.TargetProp.Type)
.InjectFrom<CloneInjection>(c.SourceProp.Value);
}
}
If you include the above CloneInjection code you will want to do this:
anotherParent.InjectFrom<CloneInjection>(parent);
instead of:
anotherParent.InjectFrom<LoopValueInjection>(parent);

Bind Menu To a List in ASP.NET

How to bind a list to ASP.NET Menu control?
try something like this .
This is just example how you bind data to the menu control using asp.net.. you can bind list also same way like this....
Start with a IHierarcyData class that will store each string from the StringCollection...
public class MyMenuItem : IHierarchyData
{
public MyMenuItem(string s)
{
Item = s;
}
public override string ToString()
{
return Item.ToString();
}
#region IHierarchyData Members
public IHierarchicalEnumerable GetChildren()
{
return null;
}
public IHierarchyData GetParent()
{
return null;
}
public bool HasChildren
{
get { return false; }
}
public object Item
{
get; set;
}
public string Path
{
get { return string.Empty; }
}
public string Type
{
get { return string.Empty; }
}
#endregion
}
Build a class that will be the collection...
public class MyMenu : StringCollection, IHierarchicalEnumerable
{
List<IHierarchyData> _list = new List<IHierarchyData>();
public void Add(StringCollection strings)
{
foreach (string s in strings)
{
MyMenuItem i = new MyMenuItem(s);
_list.Add(i);
}
}
#region IHierarchicalEnumerable Members
public IHierarchyData GetHierarchyData(object enumeratedItem)
{
return enumeratedItem as IHierarchyData;
}
#endregion
#region IEnumerable Members
public System.Collections.IEnumerator GetEnumerator()
{
return _list.GetEnumerator();
}
#endregion
}
In the page you can now construct the menu...
MyMenu pos = new MyMenu();
StringCollection sc = new StringCollection();
sc.Add("First");
sc.Add("Second");
pos.Add(sc);
Menu1.DataSource = pos;
Menu1.DataBind();

Resources