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(); }
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; }
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); }
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); }
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); }
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(); }
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); }