上方廣告

Lady Kukki 手作糖霜餅乾

2011年6月9日 星期四

Windows Form中使用GoogleMap

儘管GoogleMap在Web上的應用已經很廣泛了,甚至現在都已經開始支援Flash了,但是在桌面應用程式的應用還是很少見,這幾天在網路上Google了一下發現網路上有個免費的元件GMap.NET可以讓我們很輕鬆的開發GoogleMap的桌面應用程式,GMap.NET不但支援NET,而且還是開放原始碼提供人家下載,在這裡講了這個多的GMap.NET的好處並不是要教大家使用GMap.NET,因為小弟不才,與其要看他們的原始碼(太複雜了,看完我頭髮也白了),不如我自己寫。
由於GoogleMap開放的API並沒有特地給NET使用的,因此唯一的方向就是使用WebBrowser嵌入到Windwos程式當中,但是這樣一來又有幾個方向要思考了。

1. 首先要考慮到的是這支AP的功能性為何?個人版的還是網路版的。
2. 是不是要進行資料庫儲取?如果有的話,那資料庫是遠端的還是本機的?
就先拿遠端來說明,一開始我在考慮遠端的時候就直接先聯想到直接採用Web的開發方式,先做出一個WebSite,在來將這個WebSite嵌入到WebBrowser當中就好了。但是這個方式在我實際進行測試後發現可行性不太高(會有許多問題產生,首先要面對的第一個問題就是showdialog會另外開啟一個IE瀏覽器的視窗,這可不是我們樂見的,會有其他問題的產生),因此這種方式我就放棄了,因此只剩下另外一種方法,使用WebService來讓Windows AP呼叫,那們這個解決方案就要合併下面本機來執行了。

本機端的方式,如果資料庫在遠端,那麼就使用WebService來呼叫,資料庫在本機端的話那就好辦了,下面文章中我會說明如何在Windows AP嵌入WebBrowser並且互相傳値。
接下來我要開始說明本文標題的程式說明,下面的程式並無對資料庫進行儲取,但是相信大家看完以下程式後,你就可以寫出資料庫的應用了。

1. 先寫一個HTML檔,並將此檔案屬性調整為內嵌資源,這樣等等才可以讀取的到該檔案,這個檔案主要的目的是要嵌入WebBrowser當中顯示用的,語法如下。
<!DOCTYPE html>
<html>
<head>
    <style type="text/css">
        body
        {
            font-family: %u5FAE%u8EDF%u6B63%u9ED1%u9AD4,Arial Unicode MS;
            font-size: 12px;
        }
    </style>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
</head>
<body onload="initialize()">
    <table style="width: 100%">
<tr>
            <td style="width: 100%; height: 450px;">
                <div id="map_canvas" style="width: 100%; height: 450px;">
                </div>
</td>
        </tr>
<tr>
            <td>
                WebBrowser %u547C%u53EB Windows Form Methods :<br />
                <input type="text" id="input_name" value="Lawrence" />
                <input type="button" value="Hello" onclick="Hello()" />
            </td>
        </tr>
</table>
</body>

<script type="text/javascript">
    var map;

    function initialize() {
        var myLatlng = new google.maps.LatLng(-34.397, 150.644);
        var myOptions = {
            zoom: 8,
            center: myLatlng,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        }
        map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

        google.maps.event.addListener(map, 'click', function(event) {
            //呼叫Windows AP的Method
            window.external.SetPoint(event.latLng.lat(), event.latLng.lng());
        });

    }

    function Hello() {
        //呼叫Windows AP的Method
        window.external.CallMessageBox(document.getElementById('input_name').value);
    }

    //提供Windows AP呼叫的Funtion
    function AddMarker(lat, lng) {

        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(lat, lng),
            map: map,
            title: "Hello World!"
        });
    }
</script>

</html>

2. 接下來就是要將HTML嵌入WebBrowser當中,語法如下。
private void Form2_Load(object sender, EventArgs e)
{
    //WinForm.Resource1.test =>為HTML檔的本機資源
    webBrowser1.DocumentText = WinForm.Resource1.test;

}


3. 在Winform當中撰寫出要給javascript呼叫的Method和要呼叫javascript呼叫的Function
//javascript呼叫的Method
public void CallMessageBox(string message)
{
    MessageBox.Show(message);
}

//javascript呼叫的Method
public void SetPoint(string lat, string lng)
{
    this.textBox_Lat.Text = lat;
    this.textBox_Lng.Text = lng;
}

//javascript呼叫的Function
private void button_CallWebBrowser_Click(object sender, EventArgs e)
{
    if (!string.IsNullOrEmpty(this.textBox_Lat.Text.Trim()) && !string.IsNullOrEmpty(this.textBox_Lng.Text.Trim()))
        this.webBrowser1.Navigate("javascript:AddMarker('" + this.textBox_Lat.Text.Trim() + "','" + this.textBox_Lng.Text.Trim() + "');void(0);");
    else
        MessageBox.Show("Lat && Lng 不得為空!!");
}

4. 看起來似乎大功告成了,但是執行下去卻出現JavaScript的錯誤訊息(下圖),window.external的功用是用來控制視窗的操作,但就錯誤訊息看來,JavaScript似乎跟它不熟。因此只好網路上找答案了。

MSDN當中說到 WebBrowser.ObjectForScripting 屬性主要的功能是【取得或設定指令碼可存取的物件,這個指令碼包含在 WebBrowser 控制項中所顯示的 Web 網頁內。】
使用這個屬性,可啟用 WebBrowser 控制項所裝載之 Web 網頁與包含 WebBrowser 控制項之應用程式間的通訊。 這個屬性可讓您整合動態超文字標記語言 (DHTML) 程式碼與用戶端應用程式程式碼。 指定給這個屬性的物件可讓 Web 網頁指令碼做為 window.external 物件,這個物件是為了存取主應用程式而提供的內建 DOM 物件。 

您可以將這個屬性設為任意 COM-Visible 物件,以讓指令碼可以使用這個物件的公用屬性和方法。 您可以使用 ComVisibleAttribute 標記類別,以讓該類別 COM-Visible。

若要從用戶端應用程式程式碼呼叫 Web 網頁中所定義的函式,請使用可從 Document 屬性中擷取之 HtmlDocument 物件的 HtmlDocument.InvokeScript 方法。

這句話的意思就是要我們在Class上面加[System.Runtime.InteropServices.ComVisibleAttribute(true)]是除了這個以外我們還要在Class上面加上[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]webBrowser1.ObjectForScripting = this;這樣這個功能才可正常Work。

最後產生的結果如下圖所示。

本文附件 : 
WinFormGoogleMap.zip,2017.06.01將檔案搬移到Github上,請到此處下載範例檔案。