I currently have a button in a table view. I have a custom cell class and an update cell method.
public void UpdateCell (string subtitle2)
{
call.SetTitle(subtitle2, UIControlState.Normal);
call.TouchUpInside += (object sender, EventArgs e) => {
UIApplication.SharedApplication.OpenUrl(new NSUrl("tel:" + subtitle2));
};
}
However, when i run this segment of code, i get an error.
Could not initialize an instance of the type
'MonoTouch.Foundation.NSUrl': the native 'initWithString:' method
returned nil. It is possible to ignore this condition by setting
MonoTouch.ObjCRuntime.Class.ThrowOnInitFailure to false.
Try this:
public void UpdateCell (string subtitle2)
{
//Makes a new NSUrl
var callURL = new NSUrl("tel:" + subtitle2);
call.SetTitle(subtitle2, UIControlState.Normal);
call.TouchUpInside += (object sender, EventArgs e) => {
if (UIApplication.SharedApplication.CanOpenUrl (callURL)) {
//After checking if phone can open NSUrl, it either opens the URL or outputs to the console.
UIApplication.SharedApplication.OpenUrl(callURL);
} else {
//OUTPUT to console
Console.WriteLine("Can't make call");
}
};
}
Not sure if phone calls can be simulated in the iPhone Simulator, otherwise just connect your device :-)
As mentioned in other answers, NSUrl cannot handle spaces (and some other symbols) in URL string. That symbols should be encoded before passing to the NSUrl constructor. You can do the encoding with the NSString.CreateStringByAddingPercentEscapes method.
Another way is using of the .NET Uri class:
new NSUrl(new Uri("tel:" + subtitle2).AbsoluteUri)
The issue you might encounter here is parsing of the schema by the Uri class. To avoid it, don't use ://, so, URL strings should look as "tel:(123) 345-7890", not as "tel://(123) 345-7890"
Try
UIApplication.SharedApplication.OpenUrl(new NSUrl("tel://" + subtitle2));
This error means that calling initWithString: returned nil. ObjC init* methods can return nil while .NET constructors can't (and throws).
In general ObjC returns nil on init* selectors when the input parameters are invalid. In this case I suspect your URL format is invalid.
What's the content of your subtitle2 variable ?
I resolved the same problem, after trying various ways, by finally figuring out that there should not be any spaces (instead of e.g. 1800 111 222 333, should be like 1800111222333) between numbers to make call in iOS.
number = number.Replace(" ", "");
NSUrl url = new NSUrl(string.Format(#"telprompt://{0}", number));
return UIApplication.SharedApplication.OpenUrl(url);
Related
I am working on a cefsharp based browser and i am trying to implement a search engine into the browser, but the code I have tried docent work, it doesn't really have any errors but when i star the project and type something i the text field nothing happens and it dosent load the search engine i entered into the code, the only time the textbox loads anything is when a url is typed.
This is the code used in the browser that docent work
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.Load(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + WebUtility.HtmlEncode(url);
WebUI.Load(searchUrl);
}
}
i have also tried
void LoadURl(String url)
{
if (url.StartsWith("http"))
{
WebUI.Load(url);
}
else
{
WebUI.Load(url);
}
}
i was also suggested to try
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
WebUI.LoadUrl(searchUrl);
}
}
We have here really few Information on how your code works. But what I notice is that you use WebUtility.HtmlEncode for the search query. WebUtility has also a WebUtility.UrlEncode Method, that how I understand your question makes more sense it the context. This is the documentation for the method: https://learn.microsoft.com/de-de/dotnet/api/system.net.webutility.urlencode
The Url you are generating is invalid. You need to use Uri.EscapeDataString to convert the url param into a string that can be appended to a url.
// For this example we check if a well formed absolute Uri was provided
// and load that Url, all others will be loaded using the search engine
// e.g. https://github.com will load directly, attempting to load
// github.com will load the search engine with github.com as the query.
//
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
chromiumWebBrowser.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
chromiumWebBrowser.LoadUrl(searchUrl);
}
nothing happens and it dosent load the search engine
You need to subscribe to the LoadError event to get actual error messages. It's up to you to display errors to the user. The following is a basic example:
chromiumWebBrowser.LoadError += OnChromiumWebBrowserLoadError;
private void OnChromiumWebBrowserLoadError(object sender, LoadErrorEventArgs e)
{
//Actions that trigger a download will raise an aborted error.
//Aborted is generally safe to ignore
if (e.ErrorCode == CefErrorCode.Aborted)
{
return;
}
var errorHtml = string.Format("<html><body><h2>Failed to load URL {0} with error {1} ({2}).</h2></body></html>",
e.FailedUrl, e.ErrorText, e.ErrorCode);
_ = e.Browser.SetMainFrameDocumentContentAsync(errorHtml);
}
For testing purposes you can also copy and paste the searchUrl string you've generated and try loading it in Chrome to see what happens, you should also get an error.
I've created a dictionary like so:
public Dictionary<string, string> myValues = new Dictionary<string, string>();
Then in my start method I'm filling out my dictionary like so:
void Start()
{
myValues.Add("device one", "11111111111111");
}
And what I'm trying to do is check the value that I've created in my dictionary, in the above example it would be the 1111111111111, against a string value that is being read in remotely. The check I'm doing is this:
void Update ()
{
// Spawn a model based on the signal the ipad has recievied.
if( myValues["device one"] == outputContent.text)
{
Instantiate(model1, new Vector3(-2.5f, 3.0f,0), Quaternion.identity);
}
}
The message is getting parsed from a wrapper class that takes information from native ipad stuff and passes it direct to unity. The method for getting the message is this:
private void AppendString(string message)
{
outputContent.text += "\n" + message;
}
Now, the thing is, the message getting passed works. When I run my code, the screen gets filled with the information I want. But when I try to check the values I've stored against the ones getting sent in, nothing happens.
How I got my initial hard coded value was by first reading them in from the AppendString method. And I've double checked them to make sure I've got the correct information down.
Can someone please tell me if I'm comparing the values held within my dictionary, to those being read in, is correct?
There's a couple of 'suspicious' spots.
Here, you add \n, are you sure that's included in the dictionary's value?
outputContent.text += "\n" + message;
Also, make sure you compare the strings properly. It may even be a capitalization problem, something that's bitten me many times. Try for instance:
if(String.Equals(myValues["device one"], outputContent.text, StringComparison.OrdinalIgnoreCase)
better replace following line
if( myValues["device one"] == outputContent.text)
with:
if( myValues["device one"].Equals(outputContent.text))
I'm quite new in programming multi-threading and I could not understand from the xelium example how I could execute a javascript and get the return value.
I have tested:
browser.GetMainFrame().ExecuteJavaScript("SetContent('my Text.')", null, 0);
the javascript is executed, but I this function don’t allow me to get the return value.
I should execute the following function to get all the text the user have written in the box..
browser.GetMainFrame().ExecuteJavaScript("getContent('')", null, 0);
the function TryEval should do this…
browser.GetMainFrame().V8Context.TryEval("GetDirtyFlag", out returninformation , out exx);
But this function can’t be called from the browser, I think it must be called from the renderer? How can I do so?
I couldn’t understand the explanations about CefRenderProcessHandler and OnProcessMessageReceived.. How to register a Scriptable Object and set my javascript & parameters?
Thx for any suggestions how I could solve this!
I have been struggling with this as well. I do not think there is a way to do this synchronously...or easily :)
Perhaps what can be done is this:
From browser do sendProcessMessage with all JS information to renderer
process. You can pass all kinds of parameters to this call in a structured way so encapsulating the JS method name and params in order should not be difficult to do.
In renderer process (RenderProcessHandler onProcessMessageReceived method) do TryEval on the V8Context and get the return value via out parameters and sendProcessMessage back to the
browser process with the JS return value (Note that this supports ordinary return semantics from your JS method).You get the browser instance reference in the onProcessMessageReceived so it is as easy as this (mixed pseudo code)
browser.GetMainFrame().CefV8Context.tryEval(js-code,out retValue, out exception);
process retValue;
browser.sendProcessMessage(...);
Browser will get a callback in the WebClient in onProcessMessageReceived.
There is nothing special here in terms of setting up JS. I have for example a loaded html page with a js function in it. It takes a param as input and returns a string. in js-code parameter to TryEval I simply provide this value:
"myJSFunctionName('here I am - input param')"
It is slightly convoluted but seems like a neat workable approach - better than doing ExecuteJavaScript and posting results via XHR on custom handler in my view.
I tried this and it does work quite well indeed....and is not bad as it is all non-blocking. The wiring in the browser process needs to be done to process the response properly.
This can be extended and built into a set of classes to abstract this out for all kinds of calls..
Take a look at the Xilium demo app. Most of the necessary wiring is already there for onProcessMessage - do a global search. Look for
DemoRendererProcessHandler.cs - renderer side this is where you will invoke tryEval
DemoApp.cs - this is browser side, look for sendProcessMessage - this will initiate your JS invocation process.
WebClient.cs - this is browser side. Here you receive messages from renderer with return value from your JS
Cheers.
I resolved this problem by returning the result value from my JavaScript function back to Xilium host application via an ajax call to a custom scheme handler. According to Xilium's author fddima it is the easiest way to do IPC.
You can find an example of how to implement a scheme handler in the Xilium's demo app.
Check out this post: https://groups.google.com/forum/#!topic/cefglue/CziVAo8Ojg4
using System;
using System.Windows.Forms;
using Xilium.CefGlue;
using Xilium.CefGlue.WindowsForms;
namespace CefGlue3
{
public partial class Form1 : Form
{
private CefWebBrowser browser;
public Form1()
{
InitializeCef();
InitializeComponent();
}
private static void InitializeCef()
{
CefRuntime.Load();
CefMainArgs cefArgs = new CefMainArgs(new[] {"--force-renderer-accessibility"});
CefApplication cefApp = new CefApplication();
CefRuntime.ExecuteProcess(cefArgs, cefApp);
CefSettings cefSettings = new CefSettings
{
SingleProcess = false,
MultiThreadedMessageLoop = true,
LogSeverity = CefLogSeverity.ErrorReport,
LogFile = "CefGlue.log",
};
CefRuntime.Initialize(cefArgs, cefSettings, cefApp);
}
private void Form1_Load(object sender, EventArgs e)
{
browser = new CefWebBrowser
{
Visible = true,
//StartUrl = "http://www.google.com",
Dock = DockStyle.Fill,
Parent = this
};
Controls.Add(browser);
browser.BrowserCreated += BrowserOnBrowserCreated;
}
private void BrowserOnBrowserCreated(object sender, EventArgs eventArgs)
{
browser.Browser.GetMainFrame().LoadUrl("http://www.google.com");
}
}
}
using Xilium.CefGlue;
namespace CefGlue3
{
internal sealed class CefApplication : CefApp
{
protected override CefRenderProcessHandler GetRenderProcessHandler()
{
return new RenderProcessHandler();
}
}
internal sealed class RenderProcessHandler : CefRenderProcessHandler
{
protected override void OnWebKitInitialized()
{
CefRuntime.RegisterExtension("testExtension", "var test;if (!test)test = {};(function() {test.myval = 'My Value!';})();", null);
base.OnWebKitInitialized();
}
}
}
Edit: Sorry - now that I've understood the problem a bit better, I think my problem lies elsewhere
I have 2 asynchronus requests.
The first is this:
public void DownloadWebData(Uri apiUrl)
{
WebClient client = new WebClient();
client.DownloadDataCompleted += DownloadDataCompleted;
client.DownloadDataAsync(apiUrl);
}
public void DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
string result = System.Text.Encoding.UTF8.GetString (e.Result);
Uri downloadLink = (GetUri(result));
}
Basically it makes a simple url based API request to a remote webserver which returns some basic textual data over http. GetUri() just parses that data to extract an address from the data for an image to download.
I'm then using imageLoader in monotouch.dialog to download the image. All code is in the same class.
Edit: added the imageLoader code (I left the Console lines in because they serve reasonably well as comments).
public void downloadImage (Uri imageUri)
{
var tmp_img = ImageLoader.DefaultRequestImage (imageUri, this);
if (tmp_img != null)
{
adView.Image = tmp_img;
Console.WriteLine ("Image already cached, displaying");
}
else
{
adView.Image = UIImage.FromFile ("Images/downloading.jpg");
Console.WriteLine ("Image not cached. Using placeholder.");
}
}
public void UpdatedImage (System.Uri uri)
{
adView.Image = ImageLoader.DefaultRequestImage(uri, this);
}
You missed to check if e.Result actually contains something. The download might as well have failed and e.Result is null. Add some basic error handling to your code.
if you are using DownloadWebData inside a for loop, it will be better you generate seperate functions for DownloadDataCompleted event.
You can use anonymous function inside DownloadWebData().
client.DownloadDataCompleted +=(s,e)=>{
string result = System.Text.Encoding.UTF8.GetString (e.Result);
Uri downloadLink = (GetUri(result));
};
After realizing I was asking the wrong question, I finally figured it out here:
Hand back control to main UI thread to update UI after asynchronus image download
public void FindCityName()
{
string url = "http://maps.google.com/maps/geo?q=39.920794,32.853902&output=json&oe=utf8&sensor=true&key=MYKEY";
var w = new WebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted").Subscribe(r =>
{
var deserialized = JsonConvert.DeserializeObject<RootObject>(r.EventArgs.Result);
string s = deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
/// setCity() and City=s produce the same thing
setCity(s);
City = s;
//foreach (var item in deserialized.Placemark)
//{
// //MessageBox.Show(item.AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName);
// City = (string)item.AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
//}
//Problem here >>>>>
////MessageBox.Show(City);
});
w.DownloadStringAsync(new Uri(url));
}
Problem:
I am working on a windows phone 7 application and I need to find the "City Name" from GPS coordinates in order to move forward...
I found the code above on the internet and tried it. I can see the city name by using these codes(Message.Box(City) show exactly what I want, the city name). However, this line of code
deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
which gives me the city name seems to give a volatile string value.
For example, I created a method which assigns the value of string variable "s" to the string field of my class, name City. If I try to get the City's content after calling FindCityName() method, I see that City's content is not updated.
Again, same thing happens then I call the code line under the comment "Problem here >>>>>" that MessageBox.Show(City) shows nothing new...
Can someone explain me the reason of my problem?
you put this question on my blog as well, but I will answer it here. I feel a bit responsible for putting up the sample code in the first place ;-)
I am going to assume the class containing your code looks like this:
public class MyClass
{
private void MyMethod()
{
FindCityName();
MessageBox.Show(City);
}
private void FindCityName()
{
// Code omitted - see your question
}
private string City;
}
There is nothing volatile about the string. Your problem is asynchronicity. If you look carefully you will see that I use an observable that fires when the DownloadStringCompleted is fired. The code inside Observable.Event is only called when the download is finished but that happens asynchronously. But what I assume you do is call the FindCityName method and then directly trying to access results like I show in the MyMethod method. That's like directly wanting the result after firing the request. The results are not in yet! It's like a web page downloading - it takes a while. You can fix that with a callback, something like this:
public class MyClass
{
private void MyMethod()
{
FindName();
}
public void FindCityName()
{
string url = "http://maps.google.com/maps/geo?q=39.920794,32.853902&output=json&oe=utf8&sensor=true&key=MYKEY";
var w = new WebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted").Subscribe(r =>
{
var deserialized = JsonConvert.DeserializeObject<RootObject>(r.EventArgs.Result);
City = deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
DoneDownloading();
});
w.DownloadStringAsync(new Uri(url));
}
private string City;
private void DoneDownloading
{
MessageBox.Show(City);
}
}
Does that help?
I would recommend you to use this Google Map API
http://maps.googleapis.com/maps/api/geocode/json?latlng=39.920794,32.853902&sensor=true
And once you get JSON response in your request. You can parse easily with NEWTONSOFT for wp7
WebClient wc = new WebClient();
var json = (JObject)JsonConvert.DeserializeObject(wc.DownloadString(url));
var locality= json["results"]
.SelectMany(x => x["address_components"])
.FirstOrDefault(t => t["types"].First().ToString() == "locality");
var name = locality!=null ? locality["long_name"].ToString() : "";