C#桌面应用程序不共享我的物理位置

时间:2013-01-21 09:21:33

标签: c# javascript html5

我正在尝试在Web应用程序中获取当前位置(经度和纬度),并且可以使用以下HTML5代码。

<!DOCTYPE html>
<html>
<body>
    <p id="demo">Click the button to get your coordinates:</p>
    <button onclick="getLocation()">Try It</button>
    <script>
        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 + 
                "<br>Longitude: " + position.coords.longitude;  
        }
    </script>
</body>
</html>

但我希望在桌面应用中获得用户的经纬度。没有在桌面应用程序中使用JavaScript的选项,因此我尝试使用Web浏览器访问它。 当我尝试使用webbrowser控件(IE10)从dektop应用程序访问上面创建的网页时,它不共享物理位置,当我通过按钮单击调用脚本时没有任何反应。

有人可以帮助我在桌面应用程序(C#)中获取我的位置(经度和纬度)吗?

2 个答案:

答案 0 :(得分:2)

我正在发布另一个问题的答案,因为这涉及一种完全不同的方法。

上下文

当JavaScript尝试访问IE 10中的位置对象时,系统会显示安全栏,要求您允许访问您的位置。本地驱动器或网络共享上的文件的区别在于,您不会看到始终允许访问的选项,但只有一次(允许一次)。

无论出于何种原因,此安全栏未显示在WebBrowser控件中(即使我已尝试为应用程序的.exe设置Information Bar Handling,但似乎没有有任何影响)。

这就是为什么每次脚本执行时都不会在Web浏览器控件中发生任何事情。它实际上被信息栏阻止了。

解决方案

需要做什么:

  1. 模拟应用程序内的Web服务器。我使用Simple C# Web Server类来提供内容。这样,即使本地计算机上没有Web服务器,我们也可以拦截对特定URL地址和端口的请求,并提供我们想要的内容。

  2. test1.html文档添加到项目中,并在服务器响应中使用它的内容。只需将文件添加到项目中,“Program.cs”文件旁边,并将其复制到输出目录属性值设置为始终复制

  3. 如何运作

    首先,我们需要实例化一个Web浏览器控件。然后,导航到test1.html文件。加载文档时,我们首先检查Web服务器是否未实例化。如果是这样,我们创建它的一个实例,然后我们读取并将Web浏览器的HTMl源存储在response变量中,并将其传递给WebServer构造函数。

    http://localhost:9999HttpListener注册到该前缀,因此每个对此地址的请求都将由我们的简单Web服务器提供。

    接下来,我们导航到该地址。当Web服务器收到请求时,它将传递_staticContent变量的内容,该变量在Web服务器的构造函数中赋值。

    服务器将文档传送到Web浏览器后,将触发webBrowser1_DocumentCompleted处理程序。但是这一次,我们已经拥有了Web服务器的实例,因此执行会通过else分支。需要注意的重要一点是,我们将异步等待JavaScript执行,获取位置并将其保存到HTML中隐藏的input元素。

    一个重要的评论:第一次启动应用程序时,您将无法获得任何位置。首先必须让应用程序保持打开状态,以便您可以使用自定义HTTP侦听器,然后执行我在其他answer中描述的步骤,浏览位置为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

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <meta http-equiv="X-UA-Compatible" content="IE=10" />
        <script type="text/javascript">
            window.onload = function () {
                var latitude = document.getElementById("latitude");
                var longitude = document.getElementById("longitude");
    
                function getLocation() {
                    if (navigator.geolocation) {
                        navigator.geolocation.getCurrentPosition(showPosition);
                    }
                    else { }
                }
                function showPosition(position) {
                    latitude.value = position.coords.latitude;
                    longitude.value = position.coords.longitude;
                }
                getLocation();
            }
        </script>
    </head>
    <body>
        <input type="hidden" id="latitude" />
        <input type="hidden" id="longitude" />
    </body>
    </html>
    

答案 1 :(得分:0)

这可能是因为WebBrowser控件使用以前版本的Internet Explorer的兼容模式。

您可以使用FEATURE_BROWSER_EMULATION功能为Internet Explorer 每个应用程序设置默认模拟模式。这就是您在自己的应用程序中实际设置WebBrowser控件的兼容性模式的方法。

您可以按照以下链接中的指示进行配置:

Internet Feature Controls (B..C)

<强> [UPDATE]

  1. 转到互联网选项 - &gt;隐私
  2. Location部分下,确保Never allow websites to request your physical location 未选中
  3. 点击Clear Sites
  4. 打开Internet Explorer(不是您的应用程序)并浏览到包含地理位置脚本的文件的网址
  5. 触发getLocation()功能(在您的情况下,点击Try It按钮)
  6. 当浏览器在窗口下方显示包含yourSite wants to know your physical location.的安全栏时,请点击Options for this site并选择Always allow
  7. 就是这样。