</Template>
<HorizontalStack Height="Fit">
<GraphicObject Width="12" Height="10"/>
- <TreeView Name="List" Height="Fit"
- Template="#Crow.Templates.treeList.template" />
+ <VerticalStack Height="Fit" Name="ItemsContainer"/>
</HorizontalStack>
</Expandable>
</ItemTemplate>
internal static MethodInfo miAddITemp = typeof(Dictionary<string, ItemTemplate>).GetMethod ("set_Item", new Type[] { typeof(string), typeof(ItemTemplate) });
internal static MethodInfo miGetITempFromDic = typeof(Dictionary<string, ItemTemplate>).GetMethod ("get_Item", new Type[] { typeof(string) });
internal static FieldInfo fldItemTemplates = typeof(TemplatedGroup).GetField("ItemTemplates");
+ internal static MethodInfo miLoadPage = typeof(TemplatedGroup).GetMethod ("loadPage", BindingFlags.Instance | BindingFlags.NonPublic| BindingFlags.Public);
+ internal static MethodInfo miIsAlreadyExpanded = typeof(TemplatedGroup).GetMethod("emitHelperIsAlreadyExpanded", BindingFlags.Instance | BindingFlags.NonPublic);
+
internal static MethodInfo miCreateExpDel = typeof(ItemTemplate).GetMethod ("CreateExpandDelegate");
internal static FieldInfo fiFetchMethodName = typeof(ItemTemplate).GetField("fetchMethodName", BindingFlags.Instance | BindingFlags.NonPublic);
#region tree handling methods
using System.Threading;
using System.Linq;
using Crow.IML;
+using System.Diagnostics;
namespace Crow
{
#endregion
protected Group items;
- string _itemTemplate, _dataTest;
+ string _itemTemplate, dataTest;
#region events
public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged;
//but then i should test if null in msil gen
public Dictionary<string, ItemTemplate> ItemTemplates = new Dictionary<string, Crow.ItemTemplate>();
+ /// <summary>
+ /// Keep track of expanded subnodes and closed time to unload
+ /// </summary>
+ //Dictionary<GraphicObject, Stopwatch> nodes = new Dictionary<GraphicObject, Stopwatch>();
+ internal List<GraphicObject> nodes = new List<GraphicObject>();
/// <summary>
/// Item templates file path, on disk or embedded.
///
/// <value>The data property test.</value>
[XmlAttributeAttribute][DefaultValue("TypeOf")]
public string DataTest {
- get { return _dataTest; }
+ get { return dataTest; }
set {
- if (value == _dataTest)
+ if (value == dataTest)
return;
- _dataTest = value;
+ dataTest = value;
- NotifyValueChanged("DataTest", _dataTest);
+ NotifyValueChanged("DataTest", dataTest);
}
}
#endregion
if (value == data)
return;
- cancelLoadingThread ();
+ //cancelLoadingThread ();
if (data is IObservableList) {
IObservableList ol = data as IObservableList;
NotifyValueChanged ("Data", data);
- lock (CurrentInterface.LayoutMutex)
+ //lock (CurrentInterface.LayoutMutex)
ClearItems ();
if (data == null)
return;
- loadingThread = new CrowThread (this, loading);
- loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
- loadingThread.Start ();
+// loadingThread = new CrowThread (this, loading);
+// loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
+// loadingThread.Start ();
+
+ loadPage (data, items, dataTest);
NotifyValueChanged ("SelectedIndex", _selectedIndex);
NotifyValueChanged ("SelectedItem", SelectedItem);
// int i = e.Index % itemPerPage;
// (items.Children [p] as Group).InsertChild (i, e.Element);
} else
- loadItem (e.Index, items);
+ loadItem (e.Element, items, dataTest);
}
[XmlAttributeAttribute][DefaultValue("SteelBlue")]
/// <summary>
/// Items loading thread
/// </summary>
- void loading(){
- //if (!ItemTemplates.ContainsKey ("default"))
- // ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate);
-
- for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) {
- if ((bool)loadingThread?.cancelRequested) {
- this.Dispose ();
- return;
- }
- loadPage (i);
- Thread.Sleep (1);
- }
- }
+// void loading(){
+// //if (!ItemTemplates.ContainsKey ("default"))
+// // ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate);
+//
+// for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) {
+// if ((bool)loadingThread?.cancelRequested) {
+// this.Dispose ();
+// return;
+// }
+// loadPage (i);
+// Thread.Sleep (1);
+// }
+// }
void cancelLoadingThread(){
if (loadingThread != null)
loadingThread.Cancel ();
}
- void loadPage(int pageNum)
+ void loadPage(IList _data, Group page, string _dataTest)
{
#if DEBUG_LOAD
Stopwatch loadingTime = new Stopwatch ();
loadingTime.Start ();
#endif
- Group page;
- if (typeof(TabView).IsAssignableFrom (items.GetType ())||
- typeof(Menu).IsAssignableFrom (this.GetType())||
- typeof(Wrapper).IsAssignableFrom (items.GetType ())) {
- page = items;
- itemPerPage = int.MaxValue;
- } else if (typeof(GenericStack).IsAssignableFrom (items.GetType ())) {
- GenericStack gs = new GenericStack (items.CurrentInterface);
- gs.Orientation = (items as GenericStack).Orientation;
- gs.Width = items.Width;
- gs.Height = items.Height;
- gs.VerticalAlignment = items.VerticalAlignment;
- gs.HorizontalAlignment = items.HorizontalAlignment;
- page = gs;
- page.Name = "page" + pageNum;
- isPaged = true;
- } else {
- page = Activator.CreateInstance (items.GetType ()) as Group;
- page.CurrentInterface = items.CurrentInterface;
- page.Initialize ();
- page.Name = "page" + pageNum;
- isPaged = true;
- }
-
- for (int i = (pageNum - 1) * itemPerPage; i < pageNum * itemPerPage; i++) {
- if (i >= data.Count)
- break;
- if ((bool)loadingThread?.cancelRequested) {
- page.Dispose ();
- return;
- }
- loadItem (i, page);
+// if (typeof(TabView).IsAssignableFrom (items.GetType ())||
+// typeof(Menu).IsAssignableFrom (this.GetType())||
+// typeof(Wrapper).IsAssignableFrom (items.GetType ())) {
+ //page = items;
+ itemPerPage = int.MaxValue;
+// } else if (typeof(GenericStack).IsAssignableFrom (items.GetType ())) {
+// GenericStack gs = new GenericStack (items.CurrentInterface);
+// gs.Orientation = (items as GenericStack).Orientation;
+// gs.Width = items.Width;
+// gs.Height = items.Height;
+// gs.VerticalAlignment = items.VerticalAlignment;
+// gs.HorizontalAlignment = items.HorizontalAlignment;
+// page = gs;
+// page.Name = "page" + pageNum;
+// isPaged = true;
+// } else {
+// page = Activator.CreateInstance (items.GetType ()) as Group;
+// page.CurrentInterface = items.CurrentInterface;
+// page.Initialize ();
+// page.Name = "page" + pageNum;
+// isPaged = true;
+// }
+
+ for (int i = 0; i < _data.Count; i++) {
+ loadItem (_data[i], page, _dataTest);
}
- if (page == items)
- return;
- lock (CurrentInterface.LayoutMutex)
- items.AddChild (page);
+// if (page == items)
+// return;
+// lock (CurrentInterface.LayoutMutex)
+// items.AddChild (page);
#if DEBUG_LOAD
loadingTime.Stop ();
loadingTime.ElapsedMilliseconds, this.ToString());
#endif
}
- string getItempKey(Type dataType, object o){
+ string getItempKey(Type dataType, object o, string propertyName){
try {
- return dataType.GetProperty (_dataTest).GetGetMethod ().Invoke (o, null)?.ToString();
+ return dataType.GetProperty (propertyName).GetGetMethod ().Invoke (o, null)?.ToString();
} catch {
return dataType.FullName;
}
}
- protected void loadItem(int i, Group page){
- if (data [i] == null)//TODO:surely a threading sync problem
+ protected void loadItem(object o, Group page, string _dataTest){
+ if (o == null)//TODO:surely a threading sync problem
return;
GraphicObject g = null;
ItemTemplate iTemp = null;
- Type dataType = data [i].GetType ();
+ Type dataType = o.GetType ();
string itempKey = dataType.FullName;
if (_dataTest != "TypeOf")
- itempKey = getItempKey (dataType, data [i]);
+ itempKey = getItempKey (dataType, o, _dataTest);
if (ItemTemplates.ContainsKey (itempKey))
iTemp = ItemTemplates [itempKey];
(g as Expandable).GetIsExpandable = iTemp.HasSubItems;
}
- g.DataSource = data [i];
+ g.DataSource = o;
}
protected virtual void registerItemClick(GraphicObject g){
g.MouseClick += itemClick;
SelectedIndex = data.IndexOf((sender as GraphicObject).DataSource);
}
+ bool emitHelperIsAlreadyExpanded (GraphicObject go){
+ if (nodes.Contains (go))
+ return true;
+ nodes.Add (go);
+ return false;
+ }
+
protected override void Dispose (bool disposing)
{
if (disposing && loadingThread != null)
/// <param name="reader">current xml text reader</param>
/// <param name="itemTemplatePath">file containing the templates if its a dedicated one</param>
string[] parseItemTemplateTag (XmlReader reader, string itemTemplatePath = "") {
- string dataType = "default", datas = "", path = "";
+ string dataType = "default", datas = "", path = "", dataTest = "TypeOf";
while (reader.MoveToNextAttribute ()) {
if (reader.Name == "DataType")
dataType = reader.Value;
datas = reader.Value;
else if (reader.Name == "Path")
path = reader.Value;
+ else if (reader.Name == "DataTest")
+ dataTest = reader.Value;
}
reader.MoveToElement ();
if (string.IsNullOrEmpty (path)) {
itemTmpID += Guid.NewGuid ().ToString ();
Interface.Instantiators [itemTmpID] =
- new ItemTemplate (new MemoryStream (Encoding.UTF8.GetBytes (reader.ReadInnerXml ())), dataType, datas);
+ new ItemTemplate (new MemoryStream (Encoding.UTF8.GetBytes (reader.ReadInnerXml ())), dataTest, dataType, datas);
} else {
if (!reader.IsEmptyElement)
itemTmpID += path+dataType+datas;
if (!Interface.Instantiators.ContainsKey (itemTmpID))
Interface.Instantiators [itemTmpID] =
- new ItemTemplate (Interface.GetStreamFromPath (path), dataType, datas);
+ new ItemTemplate (Interface.GetStreamFromPath (path), dataTest, dataType, datas);
}
- return new string [] { dataType, itemTmpID, datas };
+ return new string [] { dataType, itemTmpID, datas, dataTest };
}
/// <summary>
/// process template and item template definition prior to
//the file contains a single template to use as default
Interface.Instantiators [itemTemplatePath] =
new ItemTemplate (itr);
- itemTemplateIds.Add (new string [] { "default", itemTemplatePath, "" });
+ itemTemplateIds.Add (new string [] { "default", itemTemplatePath, "", "TypeOf" });
break;//we should be at the end of the file
}
itemTemplateIds.Add (parseItemTemplateTag (itr, itemTemplatePath));
return;
//add the default item template if no default is defined
if (!itemTemplateIds.Any(ids=>ids[0] == "default"))
- itemTemplateIds.Add (new string [] { "default", "#Crow.DefaultItem.template", "" });
+ itemTemplateIds.Add (new string [] { "default", "#Crow.DefaultItem.template", "", "TypeOf"});
//copy item templates (review this)
foreach (string [] iTempId in itemTemplateIds) {
ctx.il.Emit (OpCodes.Ldloc_0);//load TempControl ref
public BooleanTestOnInstance HasSubItems;
string strDataType;
string fetchMethodName;
+ string dataTest;
#region CTOR
/// <summary>
/// <param name="path">IML file to parse</param>
/// <param name="_dataType">type this item will be choosen for, or member of the data item</param>
/// <param name="_fetchDataMethod">for hierarchical data, method to call for children fetching</param>
- public ItemTemplate(string path, string _dataType = null, string _fetchDataMethod = null)
+ public ItemTemplate(string path, string _dataTest = "TypeOf", string _dataType = null, string _fetchDataMethod = null)
: base(path) {
strDataType = _dataType;
fetchMethodName = _fetchDataMethod;
+ dataTest = _dataTest;
}
/// <summary>
/// <param name="path">IML fragment to parse</param>
/// <param name="_dataType">type this item will be choosen for, or member of the data item</param>
/// <param name="_fetchDataMethod">for hierarchical data, method to call for children fetching</param>
- public ItemTemplate (Stream ImlFragment, string _dataType, string _fetchDataMethod)
+ public ItemTemplate (Stream ImlFragment, string _dataTest, string _dataType, string _fetchDataMethod)
:base(ImlFragment)
{
strDataType = _dataType;
fetchMethodName = _fetchDataMethod;
+ dataTest = _dataTest;
}
/// <summary>
/// Initializes a new instance of the <see cref="Crow.ItemTemplate"/> class using the opened XmlReader in args.
/// <param name="path">XML reader positionned before or at the root node</param>
/// <param name="_dataType">type this item will be choosen for, or member of the data item</param>
/// <param name="_fetchDataMethod">for hierarchical data, method to call for children fetching</param>
- public ItemTemplate (XmlReader reader, string _dataType = null, string _fetchDataMethod = null)
+ public ItemTemplate (XmlReader reader, string _dataTest = "TypeOf" , string _dataType = null, string _fetchDataMethod = null)
:base(reader)
{
strDataType = _dataType;
fetchMethodName = _fetchDataMethod;
+ dataTest = _dataTest;
}
#endregion
Type tmpGrpType = typeof(TemplatedGroup);
Type evtType = typeof(EventHandler);
- PropertyInfo piData = tmpGrpType.GetProperty ("Data");
+ //PropertyInfo piData = tmpGrpType.GetProperty ("Data");
MethodInfo evtInvoke = evtType.GetMethod ("Invoke");
ParameterInfo [] evtParams = evtInvoke.GetParameters ();
//DM is bound to templatedGroup root (arg0)
//arg1 is the sender of the expand event
DynamicMethod dm = new DynamicMethod ("dyn_expand_" + fetchMethodName,
- typeof (void), args, true);
+ typeof (void), args,typeof(TemplatedGroup), true);
System.Reflection.Emit.Label gotoEnd;
System.Reflection.Emit.Label ifDataIsNull;
+ System.Reflection.Emit.Label gotoItemsContainerNotFound;
ILGenerator il = dm.GetILGenerator (256);
il.DeclareLocal(typeof(GraphicObject));
gotoEnd = il.DefineLabel ();
ifDataIsNull = il.DefineLabel ();
+ gotoItemsContainerNotFound = il.DefineLabel ();
il.Emit (OpCodes.Ldarg_1);//load sender of expand event
-
- il.Emit(OpCodes.Ldstr, "List");
+ il.Emit(OpCodes.Ldstr, "ItemsContainer");//load name to find
il.Emit (OpCodes.Callvirt, CompilerServices.miFindByName);
- il.Emit (OpCodes.Stloc_0);
+ il.Emit (OpCodes.Stloc_0);//save items container as loc0
- //check that 'Data' of list is not already set
+ //ensure ItemsContainer is not null
il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Callvirt, piData.GetGetMethod ());
- il.Emit (OpCodes.Brfalse, ifDataIsNull);
- il.Emit (OpCodes.Br, gotoEnd);
+ il.Emit (OpCodes.Brfalse, gotoItemsContainerNotFound);
+
+ //check that node is not already expanded
+ il.Emit (OpCodes.Ldarg_0);//push root TemplatedGroup into the stack
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Call, CompilerServices.miIsAlreadyExpanded);
+ il.Emit (OpCodes.Brtrue, gotoEnd);
+// il.Emit (OpCodes.Ldloc_0);
+// il.Emit (OpCodes.Callvirt, piData.GetGetMethod ());
+// il.Emit (OpCodes.Brfalse, ifDataIsNull);
+// il.Emit (OpCodes.Br, gotoEnd);
+
+// il.MarkLabel(ifDataIsNull);
- il.MarkLabel(ifDataIsNull);
//copy the ref of ItemTemplates list TODO: maybe find another way to share it among the nodes?
- FieldInfo fiTemplates = tmpGrpType.GetField("ItemTemplates");
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Ldarg_0);
- il.Emit (OpCodes.Ldfld, fiTemplates);
- il.Emit (OpCodes.Stfld, fiTemplates);
+// FieldInfo fiTemplates = tmpGrpType.GetField("ItemTemplates");
+// il.Emit (OpCodes.Ldloc_0);
+// il.Emit (OpCodes.Ldarg_0);
+// il.Emit (OpCodes.Ldfld, fiTemplates);
+// il.Emit (OpCodes.Stfld, fiTemplates);
//call 'fetchMethodName' from the dataSource to build the sub nodes list
- il.Emit (OpCodes.Ldloc_0);//push 'List' (of sub nodes) into the stack
- il.Emit (OpCodes.Ldarg_1);//get the dataSource of the sender
- il.Emit (OpCodes.Callvirt, CompilerServices.miGetDataSource);
+ //il.Emit (OpCodes.Ldarg_0);//load root templatedGroop
+
+ il.Emit (OpCodes.Ldarg_0);//push root TemplatedGroup into the stack
+ il.Emit (OpCodes.Ldarg_1);//load sender node of expand
+ il.Emit (OpCodes.Callvirt, CompilerServices.miGetDataSource);//get the dataSource of the sender
+
+
if (fetchMethodName != "self") {//special keyword self allows the use of recurent list<<<
if (dataType == null) {
emitGetSubData(il, dataType);
}
//set 'return' from the fetch method as 'data' of the list
- il.Emit (OpCodes.Callvirt, piData.GetSetMethod ());
+ //il.Emit (OpCodes.Callvirt, piData.GetSetMethod ());
+ il.Emit (OpCodes.Ldloc_0);//load second arg of loadPage, the sender node
+ il.Emit (OpCodes.Ldstr, dataTest);//load 3rd arg, dataTest kind on subitems
+ il.Emit (OpCodes.Callvirt, CompilerServices.miLoadPage);
+ il.Emit (OpCodes.Br, gotoEnd);
+
+ il.MarkLabel(gotoItemsContainerNotFound);
+ il.EmitWriteLine("ItemsContainer not found in ItemTemplate for " + host.ToString());
+
il.MarkLabel(gotoEnd);
il.Emit (OpCodes.Ret);
HasSubItems = (BooleanTestOnInstance)dm.CreateDelegate (typeof(BooleanTestOnInstance));
#endregion
}
-
//data is on the stack
void emitGetSubData(ILGenerator il, Type dataType){
MethodInfo miGetDatas = dataType.GetMethod (fetchMethodName, new Type[] {});