WPF で Google Map その 4
WPF で Google Maps API を利用するシリーズその 4。マーカーを利用できるとマップから位置を選択できるので、色々な機能に応用できそうだ。というわけで今回はマーカー操作を試す。
サンプル プログラム
前回サンプルからの変更点は以下。
- マーカーの追加・削除、マーカー位置へのマップ移動機能を追加
- マーカーの座標表示機能を追加
サンプル プログラムのプロジェクト一式は以下。ビルドには Visual Studio 2008 SP1、プログラムの実行には NET Framework 3.5 SP1 とネットワーク環境 (Google Maps API を使うので当たり前か...) が必要となる。
マーカーの操作
今回の実装を追加した事により map.js の内容が 100 行を越えたので、JavaScript のコードは重要な部分の抜粋に留める。
var marker = null; //! マーカー。
var map; //! マップ オブジェクト。
/**
* マップにマーカーを追加します。
* 既にマーカーが存在する場合は何もしません。
* マーカーの初期位置は、追加時点のマップ中央の座標となります。
*/
function addMarker()
{
window.external.IsExistMarker = true;
if( marker != null ) { return; }
var center = map.get_center();
marker = new google.maps.Marker( { position: center, map: map, title: "印", draggable: true });
notifyMarkerLocation( center );
// マップの中央位置が更新された時のイベント
google.maps.event.addListener( marker, 'drag', function()
{
notifyMarkerLocation( marker.position );
});
}
/**
* マップからマーカーを取り除きます。
* マーカーが存在しない場合は何もしません。
*/
function removeMarker()
{
window.external.IsExistMarker = false;
if( marker == null ) { return; }
marker.setMap();
marker = null;
notifyMarkerLocation( null );
}
/**
* マーカーの緯度・経度をマネージコードへ通知します。
*
* @param latLng マーカー座標。
*/
function notifyMarkerLocation( latLng )
{
window.external.MarkerLocation = ( latLng == null ? "" : "緯度 = " + latLng.lat() + "、経度 = " + latLng.lng() );
}
/**
* マーカーの座標へマップを移動します。
*/
function moveMapToMarker()
{
if( marker == null ) { return; }
map.setCenter( marker.position );
notifyLocation();
}
addMarker でマーカー生成と初期設定を実行。
マーカーの draggable を true にするとドラッグ移動がサポートされる。drag イベントをハンドリングすることで操作ごとにマーカー座標をマネージ コード側へ通知している。マーカー移動はマップに比べると軽いので更新通知は遅延させず、そのまま処理している。
removeMarker はマーカーを削除する。Google Maps API としてマーカー削除機能は用意されておらず、マーカー インスタンスの setMap メソッドを引数なしで実行すると消える。Google のリファレンスによれば setMap を呼び出した後にインスタンスを null にするべしとあるので、そうしている。
window.external.IsExistMarker については後述。notifyMarkerLocation と moveMapToMarker は特別なことをしていないので解説を省く。
WPF のボタン部分の更新
今回のプログラムでは、JavaScript 側でマーカーの追加・削除が行われた時、WPF 部分の「マーカーの追加・削除」と「マーカーへの移動」ボタンの状態を更新されるようにしている。
これを実現する為の window.external に関連付けられるマネージ クラスの実装は以下のようになる。
/// <summary>
/// Google Map の操作を行う JavaScript に関連付けられるクラスです。
/// </summary>
[ComVisible( true )]
public class MapHost : INotifyPropertyChanged
{
/// <summary>
/// マップ上にマーカーが配置されている事を示す値を取得または設定します。
/// </summary>
public bool IsExistMarker
{
get
{
return this._isExistMarker;
}
set
{
this._isExistMarker = value;
this.NotifyPropertyChanged( "IsExistMarker", "MarkerCommandText" );
}
}
/// <summary>
/// マーカーへ実行可能な操作を示す文字列を取得します。
/// </summary>
public string MarkerCommandText
{
get { return this._isExistMarker ? "マーカー削除" : "マーカー追加"; }
}
/// <summary>
/// マップ上にマーカーが配置されている事を示す値。
/// </summary>
private bool _isExistMarker;
#region INotifyPropertyChanged メンバ
/// <summary>
/// プロパティが変更された事を通知するイベント ハンドラ。
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// プロパティの変更を通知します。
/// </summary>
/// <param name="names">変更されたプロパティ名のコレクション。</param>
protected void NotifyPropertyChanged( params string[] names )
{
if( this.PropertyChanged != null )
{
foreach( string name in names )
{
this.PropertyChanged( this, new PropertyChangedEventArgs( name ) );
}
}
}
#endregion
}
JavaScript 側で window.external.IsExistMarker に値を設定すると MapHost.IsExistMarker が呼び出され、IsExistMarker と MarkerCommandText プロパティの更新が通知される。
「マーカーの追加・削除」ボタンの Content と「マーカーへの移動」ボタンの IsEnabled は XAML 上でこれらのプロパティにバインドされているため、この処理により JavaScript からの更新と連動するようになっている。
プログラムの実行
プログラムを実行すると、以下のようになる。
初期状態ではマーカーなし。「マーカーの追加」ボタンを押す事でマップ中央に追加されてゆく。このボタンはマーカーが存在していると「マーカーの削除」という表示に変わるので、この時に押せばマーカーが消える。
マーカーをドラッグ操作すると、ウィンドウ下部のマーカー座標がリアルタイムに更新されてゆく。
マップ全体を移動させてから「マーカーへの移動」ボタンを押すと、マーカーが中央に表示されるようにマップ全体が位置調整される。
Comments from WordPress
- 寺西弘明 2016-11-14T00:29:08Z
はじめまして。
寺西と申します。
古い記事について、ご質問させていただき恐縮ですが、WPF の WebBrowser コントロールで行えることは、iOS アプリの UIWebViewと同じでしょうか?
それとも、制限や違いがありますでしょうか?
お手数ですが、ご教授いただけますでしょうか。
よろしくお願いいたします。
- アカベコ 2016-11-14T11:45:45Z
ネイティブ層と Web ブラウザ内の JavaScript で連携可能な点については「同じ」ですが、連携方法は異なります。
また WebBrowser コントロールはシステムにインストールされている IE を wrap していると思われますので、Web ブラウザとして見た場合、WebKit ベースの UIWebView に比べて HTML5/CSS3/ESNext 対応に不足がありそうです。
c# - Add new Microsoft Edge to web browser control? - Stack Overflow
http://stackoverflow.com/questions/31773359/add-new-microsoft-edge-to-web-browser-controlこの投稿を読むとサードパーティ製アドオンを使わない限り IE となるそうです。また IE のバージョンも最新ではなく 7 時点で止まっており、これを 11 にするにはレジストリを編集する必要があるらしく、厄介ですね。
WebBrowserコントロールのIEバージョン - (。・ω・。)ノ・☆':;':
http://www2.hatenadiary.jp/entry/2013/12/20/114342この制限を受け入れられず、かつ Web フロントエンドの技術を利用したいなら WPF ではなくなってしまいますが Electron でアプリ開発するほうがクロスプラットフォーム対応もできてよいと思います。