C#桌面应用程序不共享我的物理位置
我试图在Web应用程序中获取当前位置(经度和纬度),它可以使用以下HTML5代码。
Click the button to get your coordinates:
var x = document.getElementById("demo"); function getLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(showPosition); } else { x.innerHTML = "Geolocation is not supported by this browser."; } } function showPosition(position) { x.innerHTML="Latitude: " + position.coords.latitude + "
Longitude: " + position.coords.longitude; }
但我希望在桌面应用中获得用户的经纬度。 没有在桌面应用程序中使用JavaScript的选项,因此我尝试使用Web浏览器访问它。 当我尝试使用webbrowser控件(IE10)从dektop应用程序访问上面创建的网页时,它不共享物理位置,并且当我通过按钮单击调用脚本时没有任何反应。
任何人都可以帮助我在桌面应用程序(C#)中获取我的位置(经度和纬度)吗?
我正在发布另一个问题的答案,因为这涉及一种完全不同的方法。
上下文
当JavaScript尝试访问IE 10中的位置对象时,系统会向您显示安全栏,要求您允许访问您的位置。 本地驱动器或网络共享上的文件的区别在于,您不会看到始终允许访问的选项,但只有一次( 允许一次 )。
无论出于何种原因,此安全栏不会显示在WebBrowser
控件中(即使我已尝试为应用程序的.exe
设置信息栏处理 ,但似乎没有任何效果)。
这就是为什么每次脚本执行时都不会在Web浏览器控件中发生任何事情。 它实际上被信息栏阻止了。
解决方案
需要做什么:
-
模拟应用程序内的Web服务器 。 我使用了一个简单的C#Web Server类来提供内容。 这样,即使本地计算机上没有Web服务器,我们也可以拦截对特定URL地址和端口的请求,并提供我们想要的内容。
-
将
test1.html
文档添加到项目中,并在服务器响应中使用它的内容 。 只需将文件添加到项目中,“Program.cs”文件旁边,并将其“ 复制到输出目录”属性值设置为“始终复制” 。
这个怎么运作
首先,我们需要实例化Web浏览器控件。 然后,导航到test1.html
文件。 加载文档时,我们首先检查Web服务器是否未实例化。 如果是这样,我们创建它的一个实例,然后我们读取并将Web浏览器的HTMl源存储在response
变量中,并将其传递给WebServer
构造函数。
http://localhost:9999
将HttpListener
注册到该前缀,因此每个对此地址的请求都将由我们的简单Web服务器提供。
接下来,我们导航到该地址。 当Web服务器将接收请求时,它将传递_staticContent
变量的内容,该变量在Web服务器的构造函数中赋值。
服务器将文档传送到Web浏览器后,将触发webBrowser1_DocumentCompleted
处理程序。 但这一次,我们已经拥有了Web服务器的实例,因此执行会通过else
分支。 需要注意的重要一点是,我们将异步等待JavaScript执行,获取位置并将其保存到HTML中的隐藏input
元素。
一个重要的评论 :第一次启动应用程序时,您将无法获得任何位置。 首先必须让应用程序保持打开状态,以便您可以使用自定义HTTP侦听器,然后执行我在其他答案中描述的步骤,浏览位置为http://localhost:9999
。 完成后,关闭并重新打开应用程序。
而已。 每次运行应用程序时,都会在消息框中获取位置坐标。
Form1
类文件( Form1.cs ):
public partial class Form1 : Form { WebServer _ws; WebBrowser _webBrowser1; public Form1() { InitializeComponent(); _webBrowser1 = new WebBrowser(); _webBrowser1.Visible = false; var location = Assembly.GetExecutingAssembly().Location; _webBrowser1.Navigate(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\test1.html"); _webBrowser1.DocumentCompleted += webBrowser1_DocumentCompleted; } private void Form1_Load(object sender, EventArgs e) { } async void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (_ws == null) { var html = _webBrowser1.Document.GetElementsByTagName("html"); var response = html[0].OuterHtml; _ws = new WebServer(response, "http://localhost:9999/"); _ws.Run(); _webBrowser1.Navigate("http://localhost:9999/"); } else { string latitude = ""; string longitude = ""; await Task.Factory.StartNew(() => { while (string.IsNullOrEmpty(latitude)) { System.Threading.Thread.Sleep(1000); if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { var latitudeEl = _webBrowser1.Document.GetElementById("latitude"); var longitudeEl = _webBrowser1.Document.GetElementById("longitude"); latitude = latitudeEl.GetAttribute("value"); longitude = longitudeEl.GetAttribute("value"); }); } } }); MessageBox.Show(String.Format("Latitude: {0} Longitude: {1}", latitude, longitude)); } } // credits for this class go to David // http://www.codehosting.net/blog/BlogEngine/post/Simple-C-Web-Server.aspx public class WebServer { private readonly HttpListener _listener = new HttpListener(); static string _staticContent; public WebServer(string[] prefixes, string content) { _staticContent = content; foreach (string s in prefixes) _listener.Prefixes.Add(s); _listener.Start(); } public WebServer(string content, params string[] prefixes) : this(prefixes, content) { } public void Run() { ThreadPool.QueueUserWorkItem((o) => { try { while (_listener.IsListening) { ThreadPool.QueueUserWorkItem((c) => { var ctx = c as HttpListenerContext; try { byte[] buf = Encoding.UTF8.GetBytes(_staticContent); ctx.Response.ContentLength64 = buf.Length; ctx.Response.OutputStream.Write(buf, 0, buf.Length); } catch { } // suppress any exceptions finally { // always close the stream ctx.Response.OutputStream.Close(); } }, _listener.GetContext()); } } catch { } // suppress any exceptions }); } public void Stop() { _listener.Stop(); _listener.Close(); } } }
HTML源代码( test1.html )
这可能是因为WebBrowser
控件使用以前版本的Internet Explorer的兼容模式。
您可以使用FEATURE_BROWSER_EMULATION
function为每个应用程序设置Internet Explorer的默认模拟模式。 这就是您在自己的应用程序中实际设置WebBrowser
控件的兼容性模式的方法。
您可以按照以下链接中的指示进行配置:
互联网function控制(B..C)
[UPDATE]
- 转到Internet选项 – >隐私
- 在“
Location
部分下,确保未选中“Never allow websites to request your physical location
- 单击“
Clear Sites
- 打开
Internet Explorer
(而不是您的应用程序)并浏览到包含地理位置脚本的文件的URL - 触发
getLocation()
函数(在您的情况下,单击Try It
按钮) - 当浏览器在窗口的下半部分显示安全栏时,包含
yourSite wants to know your physical location.
,单击Options for this site
然后选择“Always allow
。
就是这样。