private RootElement RenderEditItem(Item item, bool renderListInfo) { // get itemType for this item ItemType itemType = null; try { itemType = App.ViewModel.ItemTypes.Single(it => it.ID == item.ItemTypeID); } catch (Exception) { // if can't find the folder type, use the first itemType = App.ViewModel.ItemTypes[0]; } // render the primary fields Section primarySection = RenderEditItemFields(item, itemType, true); // HACK: insert a dummy element inside the primary section. This dummy element // implements IElementSizing and returns a 0-sized cell (so it is invisible). // This is to work around an issue in MT.Dialog where it doesn't honor IElementSizing // on elements that are added after a dialog is already drawn. This element must be // inserted after the first element but before the last element, to avoid losing the // rounded rectangle look of the first and last elements of a Section. if (primarySection.Count > 0) primarySection.Insert(1, new DummyElement()); // render more button var moreButton = new Button() { Background = "Images/darkgreybutton.png", Caption = "more details" }; var sse = new ButtonListElement() { Margin = 0f }; sse.Buttons.Add(moreButton); var moreSection = new Section() { sse }; // render save/delete buttons var actionButtons = new ButtonListElement() { //new Button() { Caption = "Save", Background = "Images/greenbutton.png", Clicked = SaveButton_Click }, new Button() { Caption = "Delete", Background = "Images/redbutton.png", Clicked = DeleteButton_Click }, }; actionButtons.Margin = 0f; // create the dialog with the primary section RootElement editRoot = new RootElement(item.Name) { primarySection, moreSection, new Section() { actionButtons }, }; moreButton.Clicked += (s, e) => { // remove the "more" button editRoot.Remove(moreSection); // render the non-primary fields as a new section editRoot.Insert(1, RenderEditItemFields(item, itemType, false)); // create a separate section with the advanced information (parent, type) var advancedSection = new Section(); Field field = new Field() { Name = "ParentID", DisplayName = "List", DisplayType = DisplayTypes.Lists }; advancedSection.Add(RenderEditItemField(item, field)); field = new Field() { Name = "ItemTypeID", DisplayName = "Type", DisplayType = DisplayTypes.ItemTypes }; advancedSection.Add(RenderEditItemField(item, field)); editRoot.Insert(2, advancedSection); }; return editRoot; }
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; }
// get FieldValue of this Item for the given Field // if create == true, a new FieldValue with for this Field will be created if none exists public FieldValue GetFieldValue(Field field, bool create = false) { FieldValue fieldValue = null; // initialize the dictionary if necessary if (fieldValueDict == null) fieldValueDict = new Dictionary<string, FieldValue>(); // try to get the FieldValue out of the dictionary (if it was already retrieved) if (fieldValueDict.TryGetValue(field.Name, out fieldValue) == true) return fieldValue; // get the fieldvalue associated with this field // this may fail if this item doesn't have this field set yet fieldValue = fieldValues.FirstOrDefault(fv => fv.FieldName == field.Name); if (fieldValue != null) { // store the new FieldValue in the dictionary fieldValueDict[field.Name] = fieldValue; } else { // if the caller wishes to create a new FieldValue, do so now if (create) { fieldValue = new FieldValue() { FieldName = field.Name, ItemID = this.ID, Value = FieldTypes.DefaultValue(field.FieldType) }; // store the new FieldValue in the dictionary fieldValueDict[field.Name] = fieldValue; if (fieldValues == null) fieldValues = new ObservableCollection<FieldValue>(); // add the new FieldValue in the FieldValues collection fieldValues.Add(fieldValue); } } return fieldValue; }
private Item CreateValueList(Item item, Field field, Guid itemID) { Item list; if (itemID == Guid.Empty) { list = new Item() { ID = itemID, // signal new list Name = field.Name, IsList = true, FolderID = folder.ID, ParentID = item.ID, ItemTypeID = SystemItemTypes.Reference, }; } else { // get the current value list list = CreateItemCopyWithChildren((Guid) itemID); } return list; }
// get FieldValue of this Item by FieldName // if create == true, a new FieldValue for this FieldName will be created if none exists public FieldValue GetFieldValue(string fieldName, bool create = false) { FieldValue fieldValue = null; // initialize the dictionary if necessary if (fieldValueDict == null) fieldValueDict = new Dictionary<string, FieldValue>(); // try to get the FieldValue out of the dictionary (if it was already retrieved) if (fieldValueDict.TryGetValue(fieldName, out fieldValue) == true) return fieldValue; // get the fieldvalue associated with this field // this may fail if this item doesn't have this field set yet if (fieldValues.Any(fv => fv.FieldName == fieldName)) { fieldValue = fieldValues.First(fv => fv.FieldName == fieldName); // store the new FieldValue in the dictionary fieldValueDict[fieldName] = fieldValue; return fieldValue; } if (create) { // try to find the current item's itemtype (this should succeed) ItemType it; if (ItemType.ItemTypes.TryGetValue(this.ItemTypeID, out it) == false) return null; // try to find the fieldName among the "supported" fields of the itemtype // this may fail if this itemtype doesn't support this field name Field field = it.Fields.FirstOrDefault(f => f.Name == fieldName); if (field == null) { // manufacture a synthetic, generic field which has a default FieldType field = new Field() { Name = fieldName, FieldType = FieldTypes.String }; } // delegate to GetFieldValue(Guid fieldID) return GetFieldValue(field, create); } return null; }
public Field(Field field) { Copy(field); }
public void Copy(Field obj) { if (obj == null) return; // copy all of the properties foreach (PropertyInfo pi in this.GetType().GetProperties()) { var val = pi.GetValue(obj, null); pi.SetValue(this, val, null); } }
private void RenderEditItemFields(Item item, ItemType itemtype, bool primary, bool renderListField) { // render fields foreach (Field f in itemtype.Fields.Where(f => f.IsPrimary == primary).OrderBy(f => f.SortOrder)) RenderEditItemField(item, f); if (renderListField == true) { Field field = new Field() { Name = "ParentID", DisplayName = "List", DisplayType = DisplayTypes.Lists }; RenderEditItemField(item, field); field = new Field() { Name = "ItemTypeID", DisplayName = "Type", DisplayType = DisplayTypes.ItemTypes }; RenderEditItemField(item, field); } // refresh the keyboard tabstops keyboardHelper.RefreshTabbedControls(null); }
private void RenderEditItemField(Item item, Field field) { // skip rendering a hidden field if (field.DisplayType == DisplayTypes.Hidden) return; 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 = itemCopy; } } 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; // set the container - this will be the object that will be passed // to pi.SetValue() below to poke new values into container = fieldValue; } ListBoxItem listBoxItem = new ListBoxItem(); StackPanel EditStackPanel = new StackPanel(); listBoxItem.Content = EditStackPanel; EditStackPanel.Children.Add( new TextBlock() { Text = field.DisplayName, Style = (Style)App.Current.Resources["PhoneTextNormalStyle"] }); // create a textbox (will be used by the majority of field types) double minWidth = App.Current.RootVisual.RenderSize.Width; if ((int)minWidth == 0) minWidth = ((this.Orientation & PageOrientation.Portrait) == PageOrientation.Portrait) ? 480.0 : 800.0; TextBox tb = new TextBox() { DataContext = container, MinWidth = minWidth, IsTabStop = true }; tb.SetBinding(TextBox.TextProperty, new Binding(pi.Name) { Mode = BindingMode.TwoWay }); bool notMatched = false; // render the right control based on the DisplayType switch (field.DisplayType) { case DisplayTypes.Text: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.Text } } }; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, tb.Text, null); }); tb.TabIndex = tabIndex++; tb.KeyUp += new KeyEventHandler(TextBox_KeyUp); EditStackPanel.Children.Add(tb); break; case DisplayTypes.TextArea: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.Text } } }; tb.AcceptsReturn = true; tb.TextWrapping = TextWrapping.Wrap; tb.Height = 150; tb.TabIndex = tabIndex++; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, tb.Text, null); }); EditStackPanel.Children.Add(tb); break; case DisplayTypes.Phone: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.TelephoneNumber } } }; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, tb.Text, null); }); tb.TabIndex = tabIndex++; tb.MinWidth -= 64; tb.MaxWidth = tb.MinWidth; StackPanel innerPanel = RenderImageButtonPanel(tb); ImageButton imageButton = (ImageButton)innerPanel.Children[1]; imageButton.Click += new RoutedEventHandler(delegate { PhoneNumberChooserTask chooser = new PhoneNumberChooserTask(); chooser.Completed += new EventHandler<PhoneNumberResult>((sender, e) => { if (e.TaskResult == TaskResult.OK && e.PhoneNumber != null && e.PhoneNumber != "") pi.SetValue(container, e.PhoneNumber, null); }); chooser.Show(); }); EditStackPanel.Children.Add(innerPanel); break; case DisplayTypes.Link: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.Url } } }; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, tb.Text, null); }); tb.TabIndex = tabIndex++; tb.KeyUp += new KeyEventHandler(TextBox_KeyUp); EditStackPanel.Children.Add(tb); break; case DisplayTypes.Email: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.EmailSmtpAddress } } }; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, tb.Text, null); }); tb.TabIndex = tabIndex++; tb.KeyUp += new KeyEventHandler(TextBox_KeyUp); tb.MinWidth -= 64; tb.MaxWidth = tb.MinWidth; innerPanel = RenderImageButtonPanel(tb); imageButton = (ImageButton)innerPanel.Children[1]; imageButton.Click += new RoutedEventHandler(delegate { EmailAddressChooserTask chooser = new EmailAddressChooserTask(); chooser.Completed += new EventHandler<EmailResult>((s, e) => { if (e.TaskResult == TaskResult.OK && !String.IsNullOrEmpty(e.Email)) { pi.SetValue(container, e.Email, null); // find the contact using the email address Contacts contacts = new Contacts(); contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>((sen, ev) => { // save the contact info as a new contact var contact = ev.Results.FirstOrDefault(); if (contact == null) return; ContactPickerHelper.AddContactInfo(contact, item); }); contacts.SearchAsync(e.Email, FilterKind.EmailAddress, null); } }); chooser.Show(); }); EditStackPanel.Children.Add(innerPanel); break; case DisplayTypes.Address: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.AddressStreet }, new InputScopeName() { NameValue = InputScopeNameValue.AddressCity }, new InputScopeName() { NameValue = InputScopeNameValue.AddressStateOrProvince }, new InputScopeName() { NameValue = InputScopeNameValue.AddressCountryName }, } }; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, tb.Text, null); }); tb.TabIndex = tabIndex++; tb.KeyUp += new KeyEventHandler(TextBox_KeyUp); tb.MinWidth -= 64; tb.MaxWidth = tb.MinWidth; innerPanel = RenderImageButtonPanel(tb); imageButton = (ImageButton)innerPanel.Children[1]; imageButton.Click += new RoutedEventHandler(delegate { // start the location service GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High); watcher.MovementThreshold = 20; // Use MovementThreshold to ignore noise in the signal. watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>((sender, e) => { if (e.Status == GeoPositionStatus.Ready) { // Use the Position property of the GeoCoordinateWatcher object to get the current location. GeoCoordinate co = watcher.Position.Location; tb.Text = co.Latitude.ToString("0.000") + "," + co.Longitude.ToString("0.000"); // Stop the Location Service to conserve battery power. watcher.Stop(); // also store the latlong information in a hidden LatLong FieldValue var latlong = item.GetFieldValue(FieldNames.LatLong, true); if (latlong != null) latlong.Value = tb.Text; } }); watcher.Start(); }); EditStackPanel.Children.Add(innerPanel); break; case DisplayTypes.Priority: ListPicker lp = new ListPicker() { MinWidth = minWidth, FullModeItemTemplate = (DataTemplate)App.Current.Resources["FullListPickerTemplate"], IsTabStop = true }; lp.ItemsSource = App.ViewModel.Constants.Priorities; lp.DisplayMemberPath = "Name"; int? lpval = (int?)pi.GetValue(container, null); if (lpval != null) lp.SelectedIndex = (int)lpval; else lp.SelectedIndex = 1; // HACK: hardcode to "Normal" priority. this should come from a table. lp.SelectionChanged += new SelectionChangedEventHandler(delegate { pi.SetValue(container, lp.SelectedIndex == 1 ? (int?)null : lp.SelectedIndex, null); }); lp.TabIndex = tabIndex++; EditStackPanel.Children.Add(lp); break; case DisplayTypes.Folders: ListPicker folderPicker = new ListPicker() { MinWidth = minWidth, IsTabStop = true }; folderPicker.ItemsSource = App.ViewModel.Folders; folderPicker.DisplayMemberPath = "Name"; Folder tl = App.ViewModel.Folders.FirstOrDefault(list => list.ID == folder.ID); folderPicker.SelectedIndex = App.ViewModel.Folders.IndexOf(tl); folderPicker.SelectionChanged += new SelectionChangedEventHandler(delegate { pi.SetValue(container, App.ViewModel.Folders[folderPicker.SelectedIndex].ID, null); }); folderPicker.TabIndex = tabIndex++; EditStackPanel.Children.Add(folderPicker); break; case DisplayTypes.Lists: ListPicker listPicker = new ListPicker() { MinWidth = minWidth, FullModeItemTemplate = (DataTemplate)App.Current.Resources["FullListPickerTemplate"], ExpansionMode = ExpansionMode.FullScreenOnly, IsTabStop = true }; var lists = App.ViewModel.Items. Where(i => i.FolderID == item.FolderID && i.IsList == true && i.ItemTypeID != SystemItemTypes.Reference). OrderBy(i => i.Name). ToObservableCollection(); lists.Insert(0, new Item() { ID = Guid.Empty, Name = folder.Name + " (folder)" }); listPicker.ItemsSource = lists; listPicker.DisplayMemberPath = "Name"; var listGuid = currentValue != null ? (Guid) currentValue : Guid.Empty; Item thisItem = lists.FirstOrDefault(i => i.ID == (Guid) listGuid); // if the list isn't found (e.g. ParentID == null), SelectedIndex will default to the Folder scope (which is correct for that case) listPicker.SelectedIndex = Math.Max(lists.IndexOf(thisItem), 0); listPicker.SelectionChanged += new SelectionChangedEventHandler(delegate { pi.SetValue(container, lists[listPicker.SelectedIndex].ID, null); }); listPicker.TabIndex = tabIndex++; EditStackPanel.Children.Add(listPicker); break; case DisplayTypes.DatePicker: DatePicker dp = new DatePicker() { DataContext = container, MinWidth = minWidth, IsTabStop = true }; DateTime date = Convert.ToDateTime((string)currentValue); if (date.Ticks == 0) date = DateTime.Now.Date; dp.Value = date; dp.ValueChanged += new EventHandler<DateTimeValueChangedEventArgs>(delegate { //pi.SetValue(container, dp.Value, null); pi.SetValue(container, dp.Value == null ? null : ((DateTime)dp.Value).ToString("d"), null); folder.NotifyPropertyChanged("FirstDue"); folder.NotifyPropertyChanged("FirstDueColor"); }); dp.TabIndex = tabIndex++; EditStackPanel.Children.Add(dp); break; case DisplayTypes.DateTimePicker: // create date picker DatePicker datePicker = new DatePicker() { DataContext = container, MinWidth = minWidth, IsTabStop = true }; // set up two-way data binding so that we don't have to pick up the new value in the event handler datePicker.SetBinding(DatePicker.ValueProperty, new Binding(pi.Name) { Mode = BindingMode.TwoWay }); datePicker.ValueChanged += new EventHandler<DateTimeValueChangedEventArgs>(delegate { folder.NotifyPropertyChanged("FirstDue"); folder.NotifyPropertyChanged("FirstDueColor"); }); datePicker.TabIndex = tabIndex++; EditStackPanel.Children.Add(datePicker); // create time picker TimePicker timePicker = new TimePicker() { DataContext = container, MinWidth = minWidth, IsTabStop = true }; // set up two-way data binding so that we don't have to pick up the new value in the event handler timePicker.SetBinding(TimePicker.ValueProperty, new Binding(pi.Name) { Mode = BindingMode.TwoWay }); timePicker.ValueChanged += new EventHandler<DateTimeValueChangedEventArgs>(delegate { folder.NotifyPropertyChanged("FirstDue"); folder.NotifyPropertyChanged("FirstDueColor"); }); timePicker.TabIndex = tabIndex++; EditStackPanel.Children.Add(timePicker); break; case DisplayTypes.Checkbox: CheckBox cb = new CheckBox() { DataContext = container, IsTabStop = true }; cb.SetBinding(CheckBox.IsCheckedProperty, new Binding(pi.Name) { Mode = BindingMode.TwoWay }); cb.TabIndex = tabIndex++; EditStackPanel.Children.Add(cb); break; case DisplayTypes.TagList: TextBox taglist = new TextBox() { MinWidth = minWidth, IsTabStop = true }; taglist.KeyUp += new KeyEventHandler(TextBox_KeyUp); taglist.TabIndex = tabIndex++; RenderEditItemTagList(taglist, (Item) container, pi); EditStackPanel.Children.Add(taglist); break; case DisplayTypes.ImageUrl: // TODO: wire up to picture picker, and upload to an image service break; case DisplayTypes.LinkArray: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.Url } } }; tb.AcceptsReturn = true; tb.TextWrapping = TextWrapping.Wrap; tb.Height = 150; tb.TabIndex = tabIndex++; tb.ClearValue(TextBox.TextProperty); if (!String.IsNullOrEmpty((string) currentValue)) { try { var linkList = JsonConvert.DeserializeObject<List<Link>>((string)currentValue); tb.Text = String.Concat(linkList.Select(l => l.Name != null ? l.Name + "," + l.Url + "\n" : l.Url + "\n").ToList()); } catch (Exception) { } } tb.LostFocus += new RoutedEventHandler(delegate { // the expected format is a newline-delimited list of Name, Url pairs var linkArray = tb.Text.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); }); EditStackPanel.Children.Add(tb); break; case DisplayTypes.Hidden: // skip rendering break; case DisplayTypes.ContactList: Item currentContacts = CreateValueList(item, field, currentValue == null ? Guid.Empty : new Guid((string) currentValue)); var contactPicker = new ItemRefListPicker(folder, currentContacts, SystemItemTypes.Contact, pi, container) { MinWidth = minWidth, IsTabStop = true }; contactPicker.TabIndex = tabIndex++; contactPicker.MinWidth -= 84; contactPicker.MaxWidth = contactPicker.MinWidth; innerPanel = RenderImageButtonPanel(contactPicker, "/Images/button.add.png", "/Images/button.add.pressed.png"); imageButton = (ImageButton)innerPanel.Children[1]; imageButton.Click += new RoutedEventHandler(delegate { EmailAddressChooserTask chooser = new EmailAddressChooserTask(); chooser.Completed += new EventHandler<EmailResult>((s, e) => { if (e.TaskResult == TaskResult.OK && !String.IsNullOrEmpty(e.Email)) { // find the contact using the email address Contacts contacts = new Contacts(); contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>((sen, ev) => { // save the contact info as a new contact var contact = ev.Results.FirstOrDefault(); if (contact == null) return; var newContact = ContactPickerHelper.ProcessContact(contact); if (newContact != null) { // if the list doesn't yet exist, create it now if (currentContacts.ID == Guid.Empty) { Guid id = Guid.NewGuid(); currentContacts.ID = id; // enqueue the Web Request Record RequestQueue.EnqueueRequestRecord(RequestQueue.UserQueue, new RequestQueue.RequestRecord() { ReqType = RequestQueue.RequestRecord.RequestType.Insert, Body = currentContacts }); // add the list to the folder folder.Items.Add(currentContacts); StorageHelper.WriteFolder(folder); // store the list's Guid in the item's property pi.SetValue(container, id.ToString(), null); } // rebuild the image panel with a new ItemRefListPicker HandleAddedContact(currentContacts, newContact); var oldListPicker = innerPanel.Children[0] as ItemRefListPicker; contactPicker = new ItemRefListPicker(folder, currentContacts, SystemItemTypes.Contact, pi, container) { IsTabStop = true }; if (oldListPicker != null) { contactPicker.TabIndex = oldListPicker.TabIndex; contactPicker.MinWidth = oldListPicker.MinWidth; contactPicker.MaxWidth = oldListPicker.MaxWidth; } innerPanel.Children[0] = contactPicker; } }); contacts.SearchAsync(e.Email, FilterKind.EmailAddress, null); } }); chooser.Show(); }); EditStackPanel.Children.Add(innerPanel); break; case DisplayTypes.LocationList: Item currentLocations = CreateValueList(item, field, currentValue == null ? Guid.Empty : new Guid((string) currentValue)); var locationPicker = new ItemRefListPicker(folder, currentLocations, SystemItemTypes.Location, pi, container) { MinWidth = minWidth, IsTabStop = true }; locationPicker.TabIndex = tabIndex++; EditStackPanel.Children.Add(locationPicker); break; case DisplayTypes.ItemTypes: ListPicker itemTypePicker = new ListPicker() { MinWidth = minWidth, FullModeItemTemplate = (DataTemplate)App.Current.Resources["FullListPickerTemplate"], ExpansionMode = ExpansionMode.FullScreenOnly, IsTabStop = true }; var itemTypes = App.ViewModel.ItemTypes.Where(i => i.UserID != SystemUsers.System).OrderBy(i => i.Name).ToList(); itemTypePicker.ItemsSource = itemTypes; itemTypePicker.DisplayMemberPath = "Name"; ItemType thisItemType = itemTypes.FirstOrDefault(i => i.ID == (Guid) currentValue); itemTypePicker.SelectedIndex = Math.Max(itemTypes.IndexOf(thisItemType), 0); itemTypePicker.SelectionChanged += new SelectionChangedEventHandler(delegate { pi.SetValue(container, itemTypes[itemTypePicker.SelectedIndex].ID, null); }); itemTypePicker.TabIndex = tabIndex++; EditStackPanel.Children.Add(itemTypePicker); 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: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.Text } } }; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, tb.Text, null); }); tb.TabIndex = tabIndex++; tb.KeyUp += new KeyEventHandler(TextBox_KeyUp); EditStackPanel.Children.Add(tb); break; case FieldTypes.Integer: tb.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = InputScopeNameValue.Digits } } }; tb.LostFocus += new RoutedEventHandler(delegate { pi.SetValue(container, Convert.ToInt32(tb.Text), null); }); tb.TabIndex = tabIndex++; tb.KeyUp += new KeyEventHandler(TextBox_KeyUp); EditStackPanel.Children.Add(tb); break; case FieldTypes.DateTime: DatePicker dp = new DatePicker() { DataContext = container, MinWidth = minWidth, IsTabStop = true }; dp.SetBinding(DatePicker.ValueProperty, new Binding(pi.Name) { Mode = BindingMode.TwoWay }); dp.ValueChanged += new EventHandler<DateTimeValueChangedEventArgs>(delegate { pi.SetValue(container, dp.Value, null); folder.NotifyPropertyChanged("FirstDue"); folder.NotifyPropertyChanged("FirstDueColor"); }); dp.TabIndex = tabIndex++; EditStackPanel.Children.Add(dp); break; case FieldTypes.Boolean: CheckBox cb = new CheckBox() { DataContext = container, IsTabStop = true }; cb.SetBinding(CheckBox.IsEnabledProperty, new Binding(pi.Name) { Mode = BindingMode.TwoWay }); cb.TabIndex = tabIndex++; EditStackPanel.Children.Add(cb); break; } } // add the listboxitem to the listbox EditListBox.Items.Add(listBoxItem); }