【问题标题】:C# desktop application doesn't share my physical locationC# 桌面应用程序不共享我的物理位置
【发布时间】:2013-01-04 07:51:31
【问题描述】:

我正在尝试在 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#) 中获取我的位置(纬度和经度)?

【问题讨论】:

  • 您是否尝试过使用显示错误的方法重载?可以看代码here
  • 是的,我也试试。但是我的应用程序甚至没有显示该错误消息
  • 返回的document.documentMode的JS调用是什么?
  • 它不返回任何东西..
  • JavaScript 对您的WebBrowser 控件有效吗?

标签: c# javascript html


【解决方案1】:

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

背景

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

无论出于何种原因,这个安全栏没有出现在WebBrowser 控件中(即使我尝试为应用程序的.exe 设置Information Bar Handling,但它似乎没有任何效果)。

这就是为什么每次执行脚本时,Web 浏览器控件中都不会发生任何事情。居然被信息栏挡住了。

解决方案

需要做什么:

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

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

    李>

工作原理

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

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

接下来,我们导航到该地址。当 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>

【讨论】:

    【解决方案2】:

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

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

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

    Internet Feature Controls (B..C)

    [更新]

    1. 转到 Internet 选项 -> 隐私
    2. Location 部分下,确保Never allow websites to request your physical location 未选中
    3. 点击Clear Sites
    4. 打开 Internet Explorer(不是您的应用程序)并浏览到包含地理定位脚本的文件的 URL
    5. 触发getLocation()函数(在你的情况下,点击Try It按钮)
    6. 当浏览器在窗口下部显示包含yourSite wants to know your physical location. 的安全栏时,单击Options for this site 并选择Always allow

    就是这样。

    【讨论】:

    • 我已经在代码的标题部分使用元标记 更改了兼容模式。
    • 我收到“用户拒绝地理定位请求”错误。我该怎么做才能克服这个错误?
    猜你喜欢
    • 2014-09-09
    • 2014-05-23
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    相关资源
    最近更新 更多