How to use ABPeoplePickerNavigationController in MonoTouch to pick a specific email address or phone number of a contact? - xamarin.ios

I have been using the ABPeoplePickerNavigationController in a project, written in MonoTouch, to pick a specific email address or phone number of a contact.
The code set a delegate, and in the delegate I implemented the ShouldContinue method, and retrieved the contact using the Handle property of all contacts. Unfortunately, it looks like something changed, or that I used undocumented features, or that I was simply lucky, because now when I'm in the process of updating the app for iPhone 5, the code no longer works.
Edit: Ok, my initial thoughts was that this was caused by changes in MonoTouch, since there has been quite a few updates since I last worked on this app. However, I now removed it from my device and downloaded the version I have on the app store, and it crashes in the same manner, null reference exception.
This means it is an iOS upgrade that made my code non-functional.
The goal of my code:
Pick a person's specific email address, not just the person, but navigating into the details of the person, and selecting a specific email address or telephone number.
The below code deals with phone numbers only, the email code looks 95% similar.
Here is the code that constructs the picker:
var picker = new ABPeoplePickerNavigationController();
picker.Init();
picker.DisplayedProperties.Clear();
picker.DisplayedProperties.Add(ABPersonProperty.FirstName);
picker.DisplayedProperties.Add(ABPersonProperty.Phone);
var del = new PhonePickerDelegate();
picker.Delegate = del;
Here is the delegate class:
private class PhonePickerDelegate : ABPeoplePickerNavigationControllerDelegate
{
public override bool ShouldContinue(ABPeoplePickerNavigationController peoplePicker, IntPtr selectedPerson, int propertyId, int identifier)
{
peoplePicker.DismissModalViewControllerAnimated(true);
// THE NEXT LINE IS THE ONE THAT NO LONGER WORKS
var contact = peoplePicker.AddressBook.SingleOrDefault(s => s.Handle == selectedPerson) as ABPerson;
using (var phones = contact.GetPhones())
{
int index = phones.GetIndexForIdentifier(identifier);
var phone = phones.GetValues()[index];
var name = (contact.FirstName + " " + contact.MiddleName).Trim() + " " + contact.LastName;
Selected(name + ": " + phone);
}
return false;
}
public override void Cancelled(ABPeoplePickerNavigationController peoplePicker)
{
peoplePicker.DismissModalViewControllerAnimated(true);
}
}
Unfortunately this code no longer finds the correct contact, as none of the contacts has a Handle value that corresponds to the selectedPerson IntPtr value.
My questions are these:
How can I fix the above code?
Can I fix the above code?
Is there some other class/method/delegate/event or whatnot I should be using instead?

You could do something like the following:
Note that AppDelegate.navigation would be your current NavigationController
using MonoTouch.AddressBookUI;
using MonoTouch.AddressBook;
ABPeoplePickerNavigationController _contactController = new ABPeoplePickerNavigationController ();
AppDelegate.navigation.PresentViewController (_contactController, true, null);
_contactController.Cancelled += delegate {
AppDelegate.navigation.DismissViewController (true, null);
return;
};
_contactController.SelectPerson += delegate(object sender, ABPeoplePickerSelectPersonEventArgs e) {
_importedContact = e.Person;
AppDelegate.navigation.DismissViewController (true, delegate {
// What to do when you dismiss the picker here.
});
};
e.Person is only going to give you the whole contact. You would want to do something like:
e.Person.GetEmails().FirstOrDefault
Hope this helps

Related

UI thread slow to respond to Progress updaters on async Task method using VS2022 & Net6.0

I’ve run into a performance obstacle and I’m uncertain of the cause, all of this is running under VS2022 & Net6.0. As this is my 1st time using this combination of a modal windows form, and progress bar, with the work running on a background thread and two Progress objects updating the UI, the progress bar, and a text label, I don’t know where to attack the problem. Prior to placing the workload on a background thread, everything was snappy, searching a thousand files with about 600 lines of text in each, in about a minute. Naturally, the windows form was frozen during this, which is why the workload was placed on a background thread.
After doing so, the workload will be 25-50% complete before the UI starts displaying the values from the Progress objects, and overall, the entire process now takes 10x as long to complete. Progress objects aren’t skipping over any values sent to them, the UI thread just seems slow in getting the information. Likewise, if I try to drag the modal form to a new spot on the desktop it’s unresponsive for 20—30 seconds before it finally moves. One more thing, I can step through the code on the background thread and see it calling the Progress updaters, but the UI thread is just very slow in responding to them.
I could use some suggestions on how to uncover the problem or if clearly evident, point out where the likely problem could be. Here are the essential controls and methods used.
public class SearchProgressForm : Form
{
private System.Windows.Forms.Button btnSearch = new Button();
private System.Windows.Forms.TextBox txtTextSearch = new TextBox();
private System.Windows.Forms.Label lblSearchFile = new Label();
private System.Windows.Forms.ProgressBar SearchProgressBar = new ProgressBar();
public event LogSearchEventHandler SearchSucceededEvent;
protected void OnSearchSucceeded(LogSearchEventArguments p_eventArguments)
{
LogSearchEventHandler handler = SearchSucceededEvent;
if (handler != null)
{
handler(this, p_eventArguments);
}
}
private void InitializeComponent()
{
this.btnSearch.Name = "btnSearch";
this.btnSearch.Text = "Search";
this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click);
this.lblSearchFile.Text = "Searching File: ";
this.txtTextSearch.Text = "search string";
}
public SearchProgressForm() { }
private void btnSearch_Click(object sender, EventArgs e)
{
this.SearchByText(this.txtTextSearch.Text);
}
private void SearchByText(string p_searchParameter)
{
// Setup a progress report for thr ProgressBar
var _progressBarUpdate = new Progress<int>(value =>
{
this.SearchProgressBar.Value = value;
this.SearchProgressBar.Refresh();
});
var _progressFileNameUpdate = new Progress<string>(value =>
{
this.lblSearchFile.Text = "Searching File For : " + value;
this.lblSearchFile.Refresh();
});
// Start search on a backgroud thread and report progress as it occurs
Task.Run(async () => await this.SearchByStringAsync(p_searchParameter, _progressBarUpdate, _progressFileNameUpdate));
}
private async Task SearchByStringAsync(string p_searchParameter, IProgress<int> p_progressBar, IProgress<string> p_progressFileName)
{
await Task.Delay(1);
TextFileReader textFileReader = new TextFileReader();
LogSearchEventArguments logSearchEventArguments = null;
long _sessionloopCount = 0;
long _totalTextLinesCount = this.GetTotalSearchCount(p_searchParameter, SearchType.TextString);
// Get file names from SQL table
var _logFiles = DataOperations.LogFileSortableList(null);
foreach (var log in _logFiles)
{
// Format a file name to be read from the file system
string _fileName = log.Directory + "\\" + log.FileName;
p_progressFileName.Report(log.FileName);
// If we've raised an event for this file, then stop iterating over remaning text
if (logSearchEventArguments != null)
{
logSearchEventArguments = null;
break;
}
// Read in file contents from file system
List<string> _fileContents = textFileReader.ReadAndReturnStringList(_fileName);
long _fileTotalRecordCount = _fileContents.Count;
long _fileRecordCount = 0;
foreach (var _line in _fileContents)
{
if (_line.ToUpper().Contains(p_searchParameter.ToUpper()))
{
// Raise an event so search parameter and file name can be captured in another form
logSearchEventArguments =
new LogSearchEventArguments
(
"TextSearch", p_searchParameter, SearchType.TextString, true, log,
new DateTime(
Convert.ToInt32("20" + log.FileName.Substring(14, 2)),
Convert.ToInt32(log.FileName.Substring(16, 2)),
Convert.ToInt32(log.FileName.Substring(18, 2)))
);
// We found a match, so no further searching is needed in this log file,
// and it's been flagged in the DB, so raise the event to save search parameter and file name
// then break out of this loop to get the next file to search in.
this.OnSearchSucceeded(logSearchEventArguments);
break;
}
// These calcs are based on actual searches performed
_fileRecordCount++;
_sessionloopCount++;
p_progressBar.Report(Convert.ToInt32((_sessionloopCount * 100) / _totalTextLinesCount));
}
// Because we exit a search as soon as the 1st match is made, need to resynch all counts
// and update the progress bar accordingly
if (_fileRecordCount < _fileTotalRecordCount)
{
long _countDifference = _fileTotalRecordCount - _fileRecordCount;
// Add count difference to sessionLoopCount and update progress bar
_sessionloopCount += _countDifference;
p_progressBar.Report(Convert.ToInt32((_sessionloopCount * 100) / _totalTextLinesCount));
}
}
//Search is complete set Progress to 100% and report before exiting
p_progressBar.Report(100);
// Close the modal SearchForm and exit
this.Close();
}
}
I solved this problem but I'm still not certain of what caused it. I eliminated the method "private void SearchByText(string p_searchParameter)" and moved the code there into the btnSearch_Click event handler so I could call my background worker "SearchByStringAsync" directly from the button click event handler.
I also updated the EFCore NuGet Packages, which were version Net6.0 to version 6.0.4, because of single line of code in my Async background method, "var _logFiles = DataOperations.LogFileSortableList(null)".
That call returned a Sortable BindingList, using BindingList <T>. Between the NuGet updates and a minor change on a custom comparer method in my BindingList <T> class, the windows modal form now updates the ProgressBar and Label text as expected, and the form now responds immediately to user interaction.

Unity Vuforia Google VR - Can't make onPointerEnter to GameObject change material for itself

I have two 3d buttons in my scene and when I gaze into any of the buttons it will invoke OnPointerEnter callback and saving the object the pointer gazed to.
Upon pressing Fire1 on the Gamepad I apply materials taken from Resources folder.
My problem started when I gazed into the second button, and pressing Fire1 button will awkwardly changed both buttons at the same time.
This is the script I attached to both of the buttons
using UnityEngine;
using UnityEngine.EventSystems;
using Vuforia;
using System.Collections;
public class TriggerMethods : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
Material _mat;
GameObject targetObject;
Renderer rend;
int i = 0;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1"))
TukarMat();
}
public void OnPointerEnter(PointerEventData eventData)
{
targetObject = ExecuteEvents.GetEventHandler<IPointerEnterHandler>(eventData.pointerEnter);
}
public void OnPointerExit(PointerEventData eventData)
{
targetObject = null;
}
public void TukarMat()
{
Debug.Log("Value i = " + i);
if (i == 0)
{
ApplyTexture(i);
i++;
}
else if (i == 1)
{
ApplyTexture(i);
i++;
}
else if (i == 2)
{
ApplyTexture(i);
i = 0;
}
}
void ApplyTexture(int i)
{
rend = targetObject.GetComponent<Renderer>();
rend.enabled = true;
switch (i)
{
case 0:
_mat = Resources.Load("Balut", typeof(Material)) as Material;
rend.sharedMaterial = _mat;
break;
case 1:
_mat = Resources.Load("Khasiat", typeof(Material)) as Material;
rend.sharedMaterial = _mat;
break;
case 2:
_mat = Resources.Load("Alma", typeof(Material)) as Material;
rend.sharedMaterial = _mat;
break;
default:
break;
}
}
I sensed some logic error and tried making another class to only manage object the pointer gazed to but I was getting more confused.
Hope getting some helps
Thank you
TukarMat() is beeing called on both buttons when you press Fire1. If targetObject is really becoming null this should give an error on first button since it's trying to get component from a null object. Else, it'll change both as you said. Make sure OnPointerExit is beeing called.
Also, it seems you are changing the shared material.
The documentation suggests:
Modifying sharedMaterial will change the appearance of all objects using this material, and change material settings that are stored in the project too.
It is not recommended to modify materials returned by sharedMaterial. If you want to modify the material of a renderer use material instead.
So, try changing the material property instead of sharedMaterial since it'll change the material for that object only.

Got a SIGSEGV while setting the Text of my TextField from a ABPeoplePickerModule

In my App the User needs to type in some Address Information.
I provide an Addressbook Button for that since Version 1.0.
That worked fine in my previous tests, but now I get a SIGSEGV when I try to set my UITextField.Text property. This error occurs everytime when I try to Pick an Address from the PeoplePicker in MonoTouches Debug mode, when I try that on my iPhone the eror occurs randomly between setting the TextFields and pushing the next ViewController.
Is There anything wrong in my Code or is it a bug?
//AB Button Event
addressBook.TouchUpInside += delegate {
//Create new Picker
ABPeoplePickerNavigationController PP = new ABPeoplePickerNavigationController();
//Cancel Event
PP.Cancelled += delegate {
NavigationController.DismissViewController(true, null);
};
//Select Event
PP.SelectPerson += delegate(object sender, ABPeoplePickerSelectPersonEventArgs e) {
//Detailed Person View
ABPersonViewController pv = new ABPersonViewController();
//Action when clicked on a Property
pv.PerformDefaultAction += delegate(object person, ABPersonViewPerformDefaultActionEventArgs ev) {
//If the Property was an Address
if(ev.Property.ToString() == "Address"){
string lands = "", orts = "", plzs = "";
try{
//Read the Detailed Address Data from the clicked property
ABMultiValue<PersonAddress> addresses = ev.Person.GetAllAddresses();
PersonAddress[] values = addresses.GetValues();
lands = values[ev.Identifier.Value].Country.ToString();
orts = values[ev.Identifier.Value].City.ToString();
plzs = values[ev.Identifier.Value].Zip.ToString();
}catch{
Console.WriteLine("Fehlerhafte Addresse");
}
//Set the Textfield with the new information
//iPhone Simulator in Debugmode crashes here everytime
land.Text = lands;
ort.Text = orts;
plz.Text = plzs;
//Close the Module
NavigationController.DismissViewController(true, null);
}
};
//Set selected Person for the person View
pv.DisplayedPerson = e.Person;
//Open Person View with navigation from the PeoplePicker Controller
PP.PushViewController(pv, true);
};
//Open PeoplePicker Controller Module
NavigationController.PresentViewController(PP, true, null);
};
Thanks in advance!
The just released MonoTouch 6.0.5 has a fix for a similar issue.

Shared Variable in C# .Net MVC Thread

I am uploading videos to server in .Net MVC application. Since it is takes some time I am doing in a background thread. On the other hand I am tracking the upload progress and display it to the user.
Here is my code
public class MyController : Controller
{
long chunkSize = 256 * 1024;
private static string _progress = ""; //if I make nonstatic it fails
//..........
//Some codes here
//..........
//Upload file Request
public ActionResult VideoUploader()
{
var client = (VimeoClient)Session["client"];
Ticket t = client.vimeo_videos_upload_getTicket();
string path = #"E:\d2.MOV"; //Hardcoded value for testing purposes
new Thread(() => Transfer(client, t, path)).Start(); //Push file to server in background
return PartialView("_progress", "Preparing to upload...");
}
//Worker Thread
private void Transfer(VimeoClient client, Ticket t, string path)
{
FileInfo UploadFile = new FileInfo(path);
int chunks = (int)Math.Floor(Convert.ToDouble(UploadFile.Length / chunkSize));
for (int i = 0; i <= chunks; i++)
{
string output = client.PostVideo(t, i, path,(int) chunkSize);
var v = client.vimeo_videos_upload_verifyChunks(t);
double percentage = (Convert.ToDouble(i + 1) / (chunks + 1)) * 100;
_progress = percentage.ToString() + "%"; // value sharing between two actions
}
string name = client.vimeo_videos_upload_complete(path, t);
client.vimeo_videos_embed_setPreset(client.Token, "200772", name);
}
//This method is calling from front end using jQuery to display progress
public ActionResult Progress()
{
//returning updated shared "_progress" varibal
return Json(_progress, JsonRequestBehavior.AllowGet);
}
}
My problem is when I made "_progress" nonstatic variable(private static _progress) it is not working. Value is always empty.
What I trying to do is share _progress variable between main thread and new thread. But it is failing when it nonstatic.
Please help me to correct. If you have a better option please share
Thanks in advance
You should be returning some sort of "operation ID" to the client as part of the original response. The Progress method should then take this operation ID as a parameter. The upload service should then store its progress against that operation ID (e.g. in a database, to allow you to scale horizontally).
Basically, you should imagine the situation where there are multiple transfers involved - you need some way of getting the progress for the right transfer.
Instance of MyController is created per request.
After you spin the worker thread you return the page to the client and that instance is gone.
You can pass this(i.e. the controller instance) to the Transfer method like this
new Thread(() => Transfer(this, client, t, path)).Start();
and then access the _progress variable in the Transfer method like this
private void Transfer(MyController controller,
VimeoClient client, Ticket t, string path)
{
controller._progress
the page is already returned, so you'll just be able to access the instance _progress field, but then how do you update the client?
you can either
return in the view an animated gif and make a periodical request to the server with javascript OR
use a library like SignalR to 'push' the progress update to the client

How to get the tab ID from url in DotNetNuke

I have an url (e.g. http://localhost/Aanbod/Pagina.aspx) and I want to know the tab id, so I can make a friendly url with query (e.g. http://localhost/Aanbod/Pagina/QueryKey/QueryValue/).
Anyone has an idea?
Edit:
I'm not on the page itself. Want to know it from any page possible.
The url does not contain the tab id itself, so it can't be extracted.
if Pagina.aspx is a page in dotnet nuke like Home or Getting Started then you can find the tab id by
DotNetNuke.Entities.Tabs.TabController objTab = new DotNetNuke.Entities.Tabs.TabController();
DotNetNuke.Entities.Tabs.TabInfo objTabinfo = objTab.GetTabByName("Pagina", this.PortalId);
int Tabid = objTabinfo.TabID;
Well, this post is a little bit old, and I don't know if someone still looks for a solution. I had this problem recently and here is the pieces of code I wrote to solve it:
public int GetTabIDFromUrl(string url, int portalID)
{
int getTabIDFromUrl = 0;
// Try the "old" way with the TabID query string
if (url.ToLower().IndexOf("tabid") > 0)
{
Int32.TryParse(Regex.Match(url, "tabid[=/](\\d+)", RegexOptions.IgnoreCase).Groups[1].Value, out getTabIDFromUrl);
}
// When there is no result (because of advanced or human friendly or whatever Url provider)
if (getTabIDFromUrl == 0)
{
TabCollection tabs = TabController.Instance.GetTabsByPortal(portalID);
foreach (KeyValuePair<int, TabInfo> k in tabs)
{
TabInfo tab = k.Value;
if (tab.FullUrl.StartsWith(url))
{
getTabIDFromUrl = tab.TabID;
break;
}
}
}
return getTabIDFromUrl;
}
This could be a pain with sites that have a lot of pages, therefore it could be useful if you have some additional information to shrink the list that you have to loop through - e.g. a ModuleId of a module that is placed on this tab:
public int GetTabIDFromUrl(string url, int moduleID, int portalID)
{
int getTabIDFromUrl = 0;
// Try the "old" way with the TabID query string
if (url.ToLower().IndexOf("tabid") > 0)
{
Int32.TryParse(Regex.Match(url, "tabid[=/](\\d+)", RegexOptions.IgnoreCase).Groups[1].Value, out getTabIDFromUrl);
}
// When there is no result (because of advanced or human friendly or whatever Url provider)
if (getTabIDFromUrl == 0)
{
IList<ModuleInfo> modules = ModuleController.Instance.GetTabModulesByModule(moduleID);
foreach (ModuleInfo module in modules)
{
TabInfo tab = TabController.Instance.GetTab(module.TabID, portalID);
if (tab.FullUrl.StartsWith(url))
{
getTabIDFromUrl = tab.TabID;
break;
}
}
}
return getTabIDFromUrl;
}
Hope that helps someone...
Happy DNNing!
Michael
I hope this will solve your issue
http://www.willstrohl.com/Blog/EntryId/66/HOW-TO-Get-DNN-TabInfo-page-object-from-TabId
Sorry, my bad!!
Here is your answer
http://www.dotnetnuke.com/Resources/Forums/forumid/118/threadid/89605/scope/posts.aspx :)

Resources