Ejemplo n.º 1
0
 public override void ViewDidUnload()
 {
     TraceHelper.AddMessage("Add: ViewDidUnload");
     if (dialogViewController != null)
     {
         this.ViewControllers = new UIViewController[0];
     }
     dialogViewController = null;
     ListsRootElement     = null;
     AddButtons           = null;
     lists        = null;
     buttonList   = null;
     listsSection = null;
     Name         = null;
     base.ViewDidUnload();
 }
Ejemplo n.º 2
0
        private Element RenderEditItemField(Item item, Field field)
        {
            PropertyInfo pi = null;
            object currentValue = null;
            object container = null;

            // get the current field value.
            // the value can either be in a strongly-typed property on the item (e.g. Name),
            // or in one of the FieldValues
            try
            {
                // get the strongly typed property
                pi = item.GetType().GetProperty(field.Name);
                if (pi != null)
                {
                    // store current item's value for this field
                    currentValue = pi.GetValue(item, null);

                    // set the container - this will be the object that will be passed
                    // to pi.SetValue() below to poke new values into
                    container = item;
                }
            }
            catch (Exception)
            {
                // an exception indicates this isn't a strongly typed property on the Item
                // this is NOT an error condition
            }

            // if couldn't find a strongly typed property, this property is stored as a
            // FieldValue on the item
            if (pi == null)
            {
                // get current item's value for this field, or create a new FieldValue
                // if one doesn't already exist
                FieldValue fieldValue = item.GetFieldValue(field.ID, true);
                currentValue = fieldValue.Value;

                // get the value property of the current fieldvalue (this should never fail)
                pi = fieldValue.GetType().GetProperty("Value");
                if (pi == null)
                    return null;

                // set the container - this will be the object that will be passed
                // to pi.SetValue() below to poke new values into
                container = fieldValue;
            }

            // most elements will be Entry Elements - default to this
            EntryElement entryElement = new EntryElement(field.DisplayName, "", "");
            Element element = entryElement;

            bool notMatched = false;
            // render the right control based on the type
            switch (field.DisplayType)
            {
                case DisplayTypes.Text:
                    //StyledMultilineElement stringElement = new StyledMultilineElement(field.DisplayName, (string) currentValue);
                    entryElement.KeyboardType = UIKeyboardType.Default;
                    entryElement.Value = (string) currentValue;
                    entryElement.AutocorrectionType = UITextAutocorrectionType.Yes;
                    entryElement.Changed += delegate {
                        pi.SetValue(container, entryElement.Value, null); };
                    //element = stringElement;
                    break;
                case DisplayTypes.TextArea:
                    MultilineEntryElement multilineElement = new MultilineEntryElement(field.DisplayName, (string) currentValue) { Lines = 3 };
                    multilineElement.Changed += delegate { pi.SetValue(container, multilineElement.Value, null); };
                    //var multilineElement = new MultilineEntryElement3(field.DisplayName, (string) currentValue) { Editable = true };
                    //multilineElement.Changed += delegate { pi.SetValue(container, multilineElement.Value, null); };
                    element = multilineElement;
                    //entryElement.Value = (string) currentValue;
                    //entryElement.Changed += delegate { pi.SetValue(container, entryElement.Value, null); };
                    break;
                case DisplayTypes.Phone:
                    entryElement.Value = (string) currentValue;
                    entryElement.KeyboardType = UIKeyboardType.PhonePad;
                    entryElement.Changed += delegate { pi.SetValue(container, entryElement.Value, null); };
                    break;
                case DisplayTypes.Link:
                    entryElement.Value = (string) currentValue;
                    entryElement.KeyboardType = UIKeyboardType.Url;
                    entryElement.Changed += delegate { pi.SetValue(container, entryElement.Value, null); };
                    break;
                case DisplayTypes.Email:
                    entryElement.Value = (string) currentValue;
                    entryElement.KeyboardType = UIKeyboardType.EmailAddress;
                    entryElement.Changed += delegate { pi.SetValue(container, entryElement.Value, null); };
                    break;
                case DisplayTypes.Address:
                    entryElement.Value = (string) currentValue;
                    entryElement.AutocorrectionType = UITextAutocorrectionType.Yes;
                    entryElement.Changed += delegate { pi.SetValue(container, entryElement.Value, null); };
                    break;
                case DisplayTypes.Priority:
                    var priorities = new RadioGroup(field.DisplayName, 0);
                    priorities.Selected =
                        ((int?) currentValue) != null ?
                        (int) currentValue :
                        1;  // HACK: hardcode to "Normal" priority.  this should come from a table.
                    var priSection = new Section();
                    priSection.AddAll(
                        from pr in App.ViewModel.Constants.Priorities
                             select (Element) new RadioEventElement(pr.Name, field.DisplayName));
                    var priorityElement = new ThemedRootElement(field.DisplayName, priorities) { priSection };
                    // augment the radio elements with the right index and event handler
                    int i = 0;
                    foreach (var radio in priorityElement[0].Elements)
                    {
                        RadioEventElement radioEventElement = (RadioEventElement) radio;
                        int index = i++;
                        radioEventElement.OnSelected += delegate { pi.SetValue(container, index, null); };
                    }
                    element = priorityElement;
                    break;
                case DisplayTypes.Lists:
                    // create a collection of lists in this folder, and add the folder as the first entry
                    var lists = App.ViewModel.Items.
                        Where(li => li.FolderID == item.FolderID && li.IsList == true && li.ItemTypeID != SystemItemTypes.Reference).
                            OrderBy(li => li.Name).
                            ToObservableCollection();
                    lists.Insert(0, new Item()
                    {
                        ID = Guid.Empty,
                        Name = folder.Name
                    });
                    // a null value for the "list" field indicates a Folder as a parent (i.e. this item is a top-level item)
                    if (currentValue == null)
                        currentValue = Guid.Empty;
                    Item currentList = lists.FirstOrDefault(li => li.ID == (Guid) currentValue);
                    var listsGroup = new RadioGroup (field.DisplayName, 0);
                    listsGroup.Selected = Math.Max(lists.IndexOf(currentList), 0);
                    var listsSection = new Section();
                    listsSection.AddAll(
                        from l in lists
                            select (Element) new RadioEventElement(l.Name, field.DisplayName));
                    var listsElement = new ThemedRootElement(field.DisplayName, listsGroup) { listsSection };
                    // augment the radio elements with the right index and event handler
                    int index = 0;
                    foreach (var radio in listsElement[0].Elements)
                    {
                        int currentIndex = index;  // make a local copy for the closure
                        RadioEventElement radioEventElement = (RadioEventElement) radio;
                        radioEventElement.OnSelected += delegate(object sender, EventArgs e)
                        {
                            pi.SetValue(container, lists[currentIndex].ID, null);
                        };
                        index++;
                    }
                    element = listsElement;
                    break;
                case DisplayTypes.DatePicker:
                    DateTime? dateTime = String.IsNullOrEmpty((string) currentValue) ? (DateTime?) null : Convert.ToDateTime((string) currentValue);
                    DateEventElement dateElement = new DateEventElement(field.DisplayName, dateTime);
                    dateElement.ValueSelected += delegate
                    {
                        pi.SetValue(container, ((DateTime)dateElement.DateValue).ToString("yyyy/MM/dd"), null);
                        folder.NotifyPropertyChanged("FirstDue");
                        folder.NotifyPropertyChanged("FirstDueColor");
                    };
                    element = dateElement;
                    break;
                case DisplayTypes.DateTimePicker:
                    DateTime? dt = String.IsNullOrEmpty((string) currentValue) ? (DateTime?) null : Convert.ToDateTime((string) currentValue);
                    DateTimeEventElement dateTimeElement = new DateTimeEventElement(field.DisplayName, dt);
                    dateTimeElement.ValueSelected += (s, e) =>
                    {
                        pi.SetValue(container, dateTimeElement.DateValue == null ? null : ((DateTime) dateTimeElement.DateValue).ToString(), null);
                        folder.NotifyPropertyChanged("FirstDue");
                        folder.NotifyPropertyChanged("FirstDueColor");
                    };
                    element = dateTimeElement;
                    break;
                case DisplayTypes.Checkbox:
                    CheckboxElement checkboxElement = new CheckboxElement(field.DisplayName, currentValue == null ? false : (bool) currentValue);
                    checkboxElement.Tapped += delegate { pi.SetValue(container, checkboxElement.Value, null); };
                    element = checkboxElement;
                    break;
                case DisplayTypes.TagList:
                    // TODO
                    element = null;
                    break;
                case DisplayTypes.ImageUrl:
                    // TODO: wire up to picture picker, and upload to an image service
                    element = null;
                    break;
                case DisplayTypes.LinkArray:
                    var linkArrayElement = new MultilineEntryElement(field.DisplayName, (string) currentValue) { Lines = 3, AcceptReturns = true };
                    if (!String.IsNullOrEmpty((string) currentValue))
                    {
                        try
                        {
                            var linkList = JsonConvert.DeserializeObject<List<Link>>((string)currentValue);
                            linkArrayElement.Value = String.Concat(linkList.Select(l => l.Name != null ? l.Name + "," + l.Url + "\n" : l.Url + "\n").ToList());
                        }
                        catch (Exception)
                        {
                        }
                    }
                    linkArrayElement.Changed += delegate
                    {
                        // the expected format is a newline-delimited list of Name, Url pairs
                        var linkArray = linkArrayElement.Value.Split(new char[] { '\r','\n' }, StringSplitOptions.RemoveEmptyEntries);
                        var linkList = new List<Link>();
                        foreach (var link in linkArray)
                        {
                            var nameval = link.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            if (nameval.Length == 0)
                                continue;
                            if (nameval.Length == 1)
                                linkList.Add(new Link() { Url = nameval[0].Trim() });
                            else
                                linkList.Add(new Link() { Name = nameval[0].Trim(), Url = nameval[1].Trim() });
                        }
                        var json = JsonConvert.SerializeObject(linkList);
                        pi.SetValue(container, json, null);
                    };
                    element = linkArrayElement;
                    break;
                case DisplayTypes.Hidden:
                    // skip rendering
                    element = null;
                    break;
                case DisplayTypes.ContactList:
                    StringElement contactsElement = new StringElement(field.DisplayName);
                    Item currentContacts = CreateValueList(item, field, currentValue == null ? Guid.Empty : new Guid((string) currentValue));
                    contactsElement.Value = CreateCommaDelimitedList(currentContacts);
                    Item contacts = new Item()
                    {
                        Items = App.ViewModel.Items.
                            Where(it => it.ItemTypeID == SystemItemTypes.Contact && it.IsList == false).
                            Select(it => new Item() { Name = it.Name, FolderID = folder.ID, ItemTypeID = SystemItemTypes.Reference, ParentID = currentContacts.ID, ItemRef = it.ID }).
                            ToObservableCollection(),
                    };
                    contactsElement.Tapped += delegate
                    {
                        // put up the list picker dialog
                        ListPickerPage listPicker = new ListPickerPage(
                            SystemItemTypes.Contact,
                            editViewController.NavigationController,
                            contactsElement,
                            pi,
                            container,
                            field.DisplayName,
                            currentContacts,
                            contacts);
                        listPicker.PushViewController();
                    };
                    element = contactsElement;
                    break;
                case DisplayTypes.LocationList:
                    StringElement locationsElement = new StringElement(field.DisplayName);
                    Item currentLocations = CreateValueList(item, field, currentValue == null ? Guid.Empty : new Guid((string) currentValue));
                    locationsElement.Value = CreateCommaDelimitedList(currentLocations);
                    Item locations = new Item()
                    {
                        Items = App.ViewModel.Items.
                            Where(it => it.ItemTypeID == SystemItemTypes.Location && it.IsList == false).
                            Select(it => new Item() { Name = it.Name, FolderID = folder.ID, ItemTypeID = SystemItemTypes.Reference, ParentID = currentLocations.ID, ItemRef = it.ID }).
                            ToObservableCollection(),
                    };
                    locationsElement.Tapped += delegate
                    {
                        // put up the list picker dialog
                        ListPickerPage listPicker = new ListPickerPage(
                            SystemItemTypes.Location,
                            editViewController.NavigationController,
                            locationsElement,
                            pi,
                            container,
                            field.DisplayName,
                            currentLocations,
                            locations);
                        listPicker.PushViewController();
                    };
                    element = locationsElement;
                    break;
                case DisplayTypes.ItemTypes:
                    var itemTypePickerElement = new ItemTypePickerElement("Type", (Guid) currentValue);
                    itemTypePickerElement.OnSelected += (sender, e) => { pi.SetValue(container, itemTypePickerElement.SelectedItemType, null); };
                    element = itemTypePickerElement;
                    break;
                default:
                    notMatched = true;
                    break;
            }

            // if wasn't able to match field type by display type, try matching by FieldType
            if (notMatched == true)
            {
                switch (field.FieldType)
                {
                    case FieldTypes.String:
                    default:
                        entryElement.KeyboardType = UIKeyboardType.Default;
                        entryElement.Value = (string) currentValue;
                        entryElement.AutocorrectionType = UITextAutocorrectionType.Yes;
                        entryElement.Changed += delegate { pi.SetValue(container, entryElement.Value, null); };
                        break;
                    case FieldTypes.Integer:
                        entryElement.Value = (string) currentValue;
                        entryElement.KeyboardType = UIKeyboardType.NumberPad;
                        entryElement.Changed += delegate { pi.SetValue(container, entryElement.Value, null); };
                        break;
                    case FieldTypes.DateTime:
                        DateTime dateTime = currentValue == null ? DateTime.Now.Date : Convert.ToDateTime ((string) currentValue);
                        DateEventElement dateElement = new DateEventElement(field.DisplayName, dateTime);
                        dateElement.ValueSelected += delegate
                        {
                            pi.SetValue(container, ((DateTime)dateElement.DateValue).ToString("yyyy/MM/dd"), null);
                            folder.NotifyPropertyChanged("FirstDue");
                            folder.NotifyPropertyChanged("FirstDueColor");
                        };
                        element = dateElement;
                        break;
                    case FieldTypes.Boolean:
                        CheckboxElement checkboxElement = new CheckboxElement(field.DisplayName, currentValue == null ? false : (bool) currentValue);
                        checkboxElement.Tapped += delegate { pi.SetValue(container, checkboxElement.Value, null); };
                        element = checkboxElement;
                        break;
                }
            }

            return element;
        }
Ejemplo n.º 3
0
        private void InitializeComponent()
        {
            // initialize controls
            Name = new MultilineEntryElement("Name", "")
            {
                Lines = 3
            };
            Name.Changed += (sender, e) =>
            {
                Name.FetchValue();
                if (String.IsNullOrWhiteSpace(Name.Value))
                {
                    listsSection.Caption = "Navigate to list:";
                }
                else
                {
                    listsSection.Caption = "Add to list:";
                }
                Name.GetImmediateRootElement().Reload(listsSection, UITableViewRowAnimation.None);
            };

            listsSection = new Section("Navigate to list:");

            var pushToTalkButton = new ButtonListElement()
            {
                new Button()
                {
                    Background = "Images/redbutton.png",
                    Caption    = "Touch to speak",
                    Clicked    = SpeechButton_Click
                },
            };

            pushToTalkButton.Margin = 0f;

            // create the dialog
            var root = new RootElement("Add Item")
            {
                new Section()
                {
                    Name,
                },
                listsSection,
                new Section()
                {
                    pushToTalkButton
                },
            };

            // create and push the dialog view onto the nav stack
            dialogViewController = new DialogViewController(root, false);
            //dialogViewController.NavigationItem.HidesBackButton = true;
            dialogViewController.Title = NSBundle.MainBundle.LocalizedString("Add Item", "Add Item");

            // set up the "pull to refresh" feature
            dialogViewController.RefreshRequested += delegate
            {
                App.ViewModel.SyncCompleteArg = dialogViewController;
                App.ViewModel.SyncComplete   += RefreshHandler;
                App.ViewModel.SyncWithService();
            };

            this.PushViewController(dialogViewController, false);
        }
Ejemplo n.º 4
0
        void Populate(object callbacks, object o, RootElement root)
        {
            MemberInfo last_radio_index = null;
            var members = o.GetType().GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public |
                                                 BindingFlags.NonPublic | BindingFlags.Instance);

            Section section = null;

            foreach (var mi in members)
            {
                Type mType = GetTypeForMember(mi);

                if (mType == null)
                    continue;

                string caption = null;
                object[] attrs = mi.GetCustomAttributes(false);
                bool skip = false;
                foreach (var attr in attrs)
                {
                    if (attr is SkipAttribute)
                        skip = true;
                    if (attr is CaptionAttribute)
                        caption = ((CaptionAttribute)attr).Caption;
                    else if (attr is SectionAttribute)
                    {
                        if (section != null)
                            root.Add(section);
                        var sa = attr as SectionAttribute;
                        section = new Section(sa.Caption, sa.Footer);
                    }
                }
                if (skip)
                    continue;

                if (caption == null)
                    caption = MakeCaption(mi.Name);

                if (section == null)
                    section = new Section();

                Element element = null;
                if (mType == typeof(string))
                {
                    PasswordAttribute pa = null;
                    AlignmentAttribute align = null;
                    EntryAttribute ea = null;
                    object html = null;
                    EventHandler invoke = null;
                    bool multi = false;

                    foreach (object attr in attrs)
                    {
                        if (attr is PasswordAttribute)
                            pa = attr as PasswordAttribute;
                        else if (attr is EntryAttribute)
                            ea = attr as EntryAttribute;
                        else if (attr is MultilineAttribute)
                            multi = true;
                        else if (attr is HtmlAttribute)
                            html = attr;
                        else if (attr is AlignmentAttribute)
                            align = attr as AlignmentAttribute;

                        if (attr is OnTapAttribute)
                        {
                            string mname = ((OnTapAttribute)attr).Method;

                            if (callbacks == null)
                            {
                                throw new Exception("Your class contains [OnTap] attributes, but you passed a null object for `context' in the constructor");
                            }

                            var method = callbacks.GetType().GetMethod(mname);
                            if (method == null)
                                throw new Exception("Did not find method " + mname);
                            invoke = delegate
                            {
                                method.Invoke(method.IsStatic ? null : callbacks, new object[0]);
                            };
                        }
                    }

                    string value = (string)GetValue(mi, o);
                    if (pa != null)
                        element = new EntryElement(caption, value) { Hint = pa.Placeholder, Password = true };
                    else if (ea != null)
                        element = new EntryElement(caption, value) { Hint = ea.Placeholder };
                    else if (multi)
                        element = new MultilineEntryElement(caption, value);
                    else if (html != null)
                        element = new HtmlElement(caption, value);
                    else
                    {
                        var selement = new StringElement(caption, value);
                        element = selement;

                        if (align != null)
                            selement.Alignment = align.Alignment;
                    }

                    if (invoke != null)
                        ((StringElement)element).Click = invoke;
                }
                else if (mType == typeof(float))
                {
                    var floatElement = new FloatElement(null, null, (int)GetValue(mi, o));
                    floatElement.Caption = caption;
                    element = floatElement;

                    foreach (object attr in attrs)
                    {
                        if (attr is RangeAttribute)
                        {
                            var ra = attr as RangeAttribute;
                            floatElement.MinValue = ra.Low;
                            floatElement.MaxValue = ra.High;
                            floatElement.ShowCaption = ra.ShowCaption;
                        }
                    }
                }
                else if (mType == typeof(bool))
                {
                    bool checkbox = false;
                    foreach (object attr in attrs)
                    {
                        if (attr is CheckboxAttribute)
                            checkbox = true;
                    }

                    if (checkbox)
                        element = new CheckboxElement(caption, value: (bool)GetValue(mi, o));
                    else
                        element = new BooleanElement(caption, (bool)GetValue(mi, o));
                }
                else if (mType == typeof(DateTime))
                {
                    var dateTime = (DateTime)GetValue(mi, o);
                    bool asDate = false, asTime = false;

                    foreach (object attr in attrs)
                    {
                        if (attr is DateAttribute)
                            asDate = true;
                        else if (attr is TimeAttribute)
                            asTime = true;
                    }

                    if (asDate)
                        element = new DateElement(caption, dateTime);
                    else if (asTime)
                        element = new TimeElement(caption, dateTime);
                    else
                        element = new DateTimeElement(caption, dateTime);
                }
                else if (mType.IsEnum)
                {
                    var csection = new Section();
                    ulong evalue = Convert.ToUInt64(GetValue(mi, o), null);
                    int idx = 0;
                    int selected = 0;

                    foreach (var fi in mType.GetFields(BindingFlags.Public | BindingFlags.Static))
                    {
                        ulong v = Convert.ToUInt64(GetValue(fi, null));

                        if (v == evalue)
                            selected = idx;

                        csection.Add(new RadioElement(MakeCaption(fi.Name)));
                        idx++;
                    }

                    element = new RootElement(caption, new RadioGroup(null, selected)) { csection };
                }
                else if (mType == typeof(ImageView))
                {
                    element = new ImageElement((ImageView)GetValue(mi, o));
                }
                else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(mType))
                {
                    var csection = new Section();
                    int count = 0;

                    if (last_radio_index == null)
                        throw new Exception("IEnumerable found, but no previous int found");
                    foreach (var e in (IEnumerable)GetValue(mi, o))
                    {
                        csection.Add(new RadioElement(e.ToString()));
                        count++;
                    }
                    int selected = (int)GetValue(last_radio_index, o);
                    if (selected >= count || selected < 0)
                        selected = 0;
                    element = new RootElement(caption, new MemberRadioGroup(null, selected, last_radio_index)) { csection };
                    last_radio_index = null;
                }
                else if (typeof(int) == mType)
                {
                    foreach (object attr in attrs)
                    {
                        if (attr is RadioSelectionAttribute)
                        {
                            last_radio_index = mi;
                            break;
                        }
                    }
                }
                else
                {
                    var nested = GetValue(mi, o);
                    if (nested != null)
                    {
                        var newRoot = new RootElement(caption);
                        Populate(callbacks, nested, newRoot);
                        element = newRoot;
                    }
                }

                if (element == null)
                    continue;

                section.Add(element);
                mappings[element] = new MemberAndInstance(mi, o);
            }
            root.Add(section);
        }
Ejemplo n.º 5
0
        private void InitializeComponent()
        {
            // initialize controls
            Name = new MultilineEntryElement("Name", "") { Lines = 3 };
            Name.Changed += (sender, e) =>
            {
                Name.FetchValue();
                if (String.IsNullOrWhiteSpace(Name.Value))
                    listsSection.Caption = "Navigate to list:";
                else
                    listsSection.Caption = "Add to list:";
                Name.GetImmediateRootElement().Reload(listsSection, UITableViewRowAnimation.None);
            };

            listsSection = new Section("Navigate to list:");

            var pushToTalkButton = new ButtonListElement()
            {
                new Button()
                {
                    Background = "Images/redbutton.png",
                    Caption = "Touch to speak",
                    Clicked = SpeechButton_Click
                },
            };
            pushToTalkButton.Margin = 0f;

            // create the dialog
            var root = new RootElement("Add Item")
            {
                new Section()
                {
                    Name,
                },
                listsSection,
                new Section()
                {
                    pushToTalkButton
                },
            };

            // create and push the dialog view onto the nav stack
            dialogViewController = new DialogViewController(root, false);
            //dialogViewController.NavigationItem.HidesBackButton = true;
            dialogViewController.Title = NSBundle.MainBundle.LocalizedString("Add Item", "Add Item");

            // set up the "pull to refresh" feature
            dialogViewController.RefreshRequested += delegate
            {
                App.ViewModel.SyncCompleteArg = dialogViewController;
                App.ViewModel.SyncComplete += RefreshHandler;
                App.ViewModel.SyncWithService();
            };

            this.PushViewController(dialogViewController, false);
        }
Ejemplo n.º 6
0
 public override void ViewDidUnload()
 {
     TraceHelper.AddMessage("Add: ViewDidUnload");
     if (dialogViewController != null)
         this.ViewControllers = new UIViewController[0];
     dialogViewController = null;
     ListsRootElement = null;
     AddButtons = null;
     lists = null;
     buttonList = null;
     listsSection = null;
     Name = null;
     base.ViewDidUnload();
 }
Ejemplo n.º 7
0
        void Populate(object callbacks, object o, RootElement root)
        {
            MemberInfo last_radio_index = null;
            var        members          = o.GetType().GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public |
                                                                 BindingFlags.NonPublic | BindingFlags.Instance);

            Section section = null;

            foreach (var mi in members)
            {
                Type mType = GetTypeForMember(mi);

                if (mType == null)
                {
                    continue;
                }

                string   caption = null;
                object[] attrs   = mi.GetCustomAttributes(false);
                bool     skip    = false;
                foreach (var attr in attrs)
                {
                    if (attr is SkipAttribute)
                    {
                        skip = true;
                    }
                    if (attr is CaptionAttribute)
                    {
                        caption = ((CaptionAttribute)attr).Caption;
                    }
                    else if (attr is SectionAttribute)
                    {
                        if (section != null)
                        {
                            root.Add(section);
                        }
                        var sa = attr as SectionAttribute;
                        section = new Section(sa.Caption, sa.Footer);
                    }
                }
                if (skip)
                {
                    continue;
                }

                if (caption == null)
                {
                    caption = MakeCaption(mi.Name);
                }

                if (section == null)
                {
                    section = new Section();
                }

                Element element = null;
                if (mType == typeof(string))
                {
                    PasswordAttribute  pa     = null;
                    AlignmentAttribute align  = null;
                    EntryAttribute     ea     = null;
                    object             html   = null;
                    EventHandler       invoke = null;
                    bool multi = false;

                    foreach (object attr in attrs)
                    {
                        if (attr is PasswordAttribute)
                        {
                            pa = attr as PasswordAttribute;
                        }
                        else if (attr is EntryAttribute)
                        {
                            ea = attr as EntryAttribute;
                        }
                        else if (attr is MultilineAttribute)
                        {
                            multi = true;
                        }
                        else if (attr is HtmlAttribute)
                        {
                            html = attr;
                        }
                        else if (attr is AlignmentAttribute)
                        {
                            align = attr as AlignmentAttribute;
                        }

                        if (attr is OnTapAttribute)
                        {
                            string mname = ((OnTapAttribute)attr).Method;

                            if (callbacks == null)
                            {
                                throw new Exception("Your class contains [OnTap] attributes, but you passed a null object for `context' in the constructor");
                            }

                            var method = callbacks.GetType().GetMethod(mname);
                            if (method == null)
                            {
                                throw new Exception("Did not find method " + mname);
                            }
                            invoke = delegate
                            {
                                method.Invoke(method.IsStatic ? null : callbacks, new object[0]);
                            };
                        }
                    }

                    string value = (string)GetValue(mi, o);
                    if (pa != null)
                    {
                        element = new EntryElement(caption, value)
                        {
                            Hint = pa.Placeholder, Password = true
                        }
                    }
                    ;
                    else if (ea != null)
                    {
                        element = new EntryElement(caption, value)
                        {
                            Hint = ea.Placeholder
                        }
                    }
                    ;
                    else if (multi)
                    {
                        element = new MultilineEntryElement(caption, value);
                    }
                    else if (html != null)
                    {
                        element = new HtmlElement(caption, value);
                    }
                    else
                    {
                        var selement = new StringElement(caption, value);
                        element = selement;

                        if (align != null)
                        {
                            selement.Alignment = align.Alignment;
                        }
                    }

                    if (invoke != null)
                    {
                        ((StringElement)element).Click = invoke;
                    }
                }
                else if (mType == typeof(float))
                {
                    var floatElement = new FloatElement(null, null, (int)GetValue(mi, o));
                    floatElement.Caption = caption;
                    element = floatElement;

                    foreach (object attr in attrs)
                    {
                        if (attr is RangeAttribute)
                        {
                            var ra = attr as RangeAttribute;
                            floatElement.MinValue    = ra.Low;
                            floatElement.MaxValue    = ra.High;
                            floatElement.ShowCaption = ra.ShowCaption;
                        }
                    }
                }
                else if (mType == typeof(bool))
                {
                    bool checkbox = false;
                    foreach (object attr in attrs)
                    {
                        if (attr is CheckboxAttribute)
                        {
                            checkbox = true;
                        }
                    }

                    if (checkbox)
                    {
                        element = new CheckboxElement(caption, value: (bool)GetValue(mi, o));
                    }
                    else
                    {
                        element = new BooleanElement(caption, (bool)GetValue(mi, o));
                    }
                }
                else if (mType == typeof(DateTime))
                {
                    var  dateTime = (DateTime)GetValue(mi, o);
                    bool asDate = false, asTime = false;

                    foreach (object attr in attrs)
                    {
                        if (attr is DateAttribute)
                        {
                            asDate = true;
                        }
                        else if (attr is TimeAttribute)
                        {
                            asTime = true;
                        }
                    }

                    if (asDate)
                    {
                        element = new DateElement(caption, dateTime);
                    }
                    else if (asTime)
                    {
                        element = new TimeElement(caption, dateTime);
                    }
                    else
                    {
                        element = new DateTimeElement(caption, dateTime);
                    }
                }
                else if (mType.IsEnum)
                {
                    var   csection = new Section();
                    ulong evalue   = Convert.ToUInt64(GetValue(mi, o), null);
                    int   idx      = 0;
                    int   selected = 0;

                    foreach (var fi in mType.GetFields(BindingFlags.Public | BindingFlags.Static))
                    {
                        ulong v = Convert.ToUInt64(GetValue(fi, null));

                        if (v == evalue)
                        {
                            selected = idx;
                        }

                        csection.Add(new RadioElement(MakeCaption(fi.Name)));
                        idx++;
                    }

                    element = new RootElement(caption, new RadioGroup(null, selected))
                    {
                        csection
                    };
                }
                else if (mType == typeof(ImageView))
                {
                    element = new ImageElement((ImageView)GetValue(mi, o));
                }
                else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(mType))
                {
                    var csection = new Section();
                    int count    = 0;

                    if (last_radio_index == null)
                    {
                        throw new Exception("IEnumerable found, but no previous int found");
                    }
                    foreach (var e in (IEnumerable)GetValue(mi, o))
                    {
                        csection.Add(new RadioElement(e.ToString()));
                        count++;
                    }
                    int selected = (int)GetValue(last_radio_index, o);
                    if (selected >= count || selected < 0)
                    {
                        selected = 0;
                    }
                    element = new RootElement(caption, new MemberRadioGroup(null, selected, last_radio_index))
                    {
                        csection
                    };
                    last_radio_index = null;
                }
                else if (typeof(int) == mType)
                {
                    foreach (object attr in attrs)
                    {
                        if (attr is RadioSelectionAttribute)
                        {
                            last_radio_index = mi;
                            break;
                        }
                    }
                }
                else
                {
                    var nested = GetValue(mi, o);
                    if (nested != null)
                    {
                        var newRoot = new RootElement(caption);
                        Populate(callbacks, nested, newRoot);
                        element = newRoot;
                    }
                }

                if (element == null)
                {
                    continue;
                }

                section.Add(element);
                mappings[element] = new MemberAndInstance(mi, o);
            }
            root.Add(section);
        }