SQLの窓

2012年10月27日


Windows Phone(C#) のデータバインドを Json.NET を使って一行で実装する( しかも XML を JSON 変換して使う )

以下の画像はこのブログの index20.rdf を表示しています



SkyDrive に移動


サンプルは、2ページ仕様で表示していますが、1ページ目の内容を再度表示しているだけです。重要なのは、Json.NET の使い方と、その為のバインド用のクラスの作成方法です。

※ データは NAVER まとめのデータを利用してテストしています
※ 結果をアプリからの投稿用の『超簡易掲示板』を使用して JSON 文字列を書き込んでいます

Windows Phone まとめリンク

Windows Phone

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using System.Diagnostics;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Xml.Linq;
using Microsoft.Phone.Tasks;

namespace DataBound_ListBox_JSON
{
	public partial class MainPage : PhoneApplicationPage
	{
		// コンストラクター
		public MainPage()
		{
			InitializeComponent();

			// ListBox コントロールのデータ コンテキストをサンプル データに設定します
			DataContext = App.ViewModel;
			this.Loaded += new RoutedEventHandler(MainPage_Loaded);

			App.mainPage = this;

		}

		private void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
		{
			if (e.Error != null)
			{
				Deployment.Current.Dispatcher.BeginInvoke(() =>
				{
					Debug.WriteLine(e.Error.Message);
				});
			}
			else
			{
				JObject RSS = null;
				JArray jsonItems = null;
				string json_string = null;
				int rowMax = 0;

				// XML 文字列を dom に変換
				XDocument dom = XDocument.Parse(e.Result);

				// dom を JSON 文字列に変換
				json_string = JsonConvert.SerializeXNode(dom.FirstNode);

				// JSON 文字列を JSON 表現可能な JObject に変換
				RSS = JObject.Parse(json_string);

				// 対象となる item の数を得る
				jsonItems = (JArray)RSS["rss"]["channel"]["item"];

				// **********************************
				// ここからテスト確認用はじまり
				// **********************************
				rowMax = jsonItems.Count;
				// トップから一覧表示
				for (int i = 0; i < rowMax; i++)
				{
					Debug.WriteLine(RSS["rss"]["channel"]["item"][i]["title"]);
					Debug.WriteLine(RSS["rss"]["channel"]["item"][i]["description"]);
					Debug.WriteLine(RSS["rss"]["channel"]["item"][i]["link"]);
				}

				Debug.WriteLine("----------------------------------");

				// 必要部分のみ(item)を JSON 文字列に戻す
				json_string = JsonConvert.SerializeObject(jsonItems);  // 必要なのはここだけ
				json_string = "{ item: " + json_string + "}";

				RSS = JObject.Parse(json_string);

				// 対象のみ
				for (int i = 0; i < rowMax; i++)
				{
					Debug.WriteLine(RSS["item"][i]["title"]);
					Debug.WriteLine(RSS["item"][i]["description"]);
					Debug.WriteLine(RSS["item"][i]["link"]);
				}

				WebClientPost.LogPost("http://localhost/php_json/log.php", json_string);
				// **********************************
				// ここまでテスト確認用の終わり
				// **********************************


				// **********************************
				// バインドは以下の一行で完了
				// **********************************
				App.ViewModel = JsonConvert.DeserializeObject<MainViewModel>(json_string);
				// データコンテキスト設定
				DataContext = App.ViewModel;


				// ロード済のフラグをセット
				App.ViewModel.IsDataLoaded = true;
			}
		}

		// ListBox で変更された選択項目を処理します
		private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			// 選択されたインデックスが -1 の場合 (選択されていない場合) は何も行いません
			if (MainListBox.SelectedIndex == -1)
				return;

			// 新しいページに移動します
			NavigationService.Navigate(
				new Uri("/DetailsPage.xaml?selectedItem=" + MainListBox.SelectedIndex, UriKind.Relative)
				);

			// 選択されたインデックスを -1 (選択されていない) にリセットします
			MainListBox.SelectedIndex = -1;
		}

		// ViewModel Items のデータを読み込みます
		private void MainPage_Loaded(object sender, RoutedEventArgs e)
		{
			if (!App.ViewModel.IsDataLoaded)
			{
				LoadData();
			}
		}

		public void LoadData()
		{

			if (App.ViewModel.IsDataLoaded)
			{
				App.ViewModel.item.Clear();
			}

			WebClient webClient = new WebClient();
			webClient.DownloadStringCompleted +=
				new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
			// 外部サービスから文字列を取得
			webClient.DownloadStringAsync(new System.Uri("http://matome.naver.jp/feed/hot"));
		}

	}
}
関連する記事

PHP による『超簡易掲示板』 / アブリケーションからの POST 検証用


タグ:JSON
posted by lightbox at 2012-10-27 23:29 | Windows Phone | このブログの読者になる | 更新情報をチェックする

2012年10月21日


WindowsPhone からの単純なインターネット投稿

SkyDrive へ移動

WebClientPost.cs

WebClientPost.LogPost("http://localhost/lightbox/test/log.php", json_string);

PHP による『超簡易掲示板』 / アブリケーションからの POST 検証用 を使用して外部ログとして利用できます。( Debug.WriteLine だととても長い文字列を簡単に取得できません )

using System;
using System.Net;
using System.Windows;

public class WebClientPost
{
	public static void LogPost(string url,string value){

		WebClient HttpClient = new WebClient();

		// ダウンロード完了後に呼び出されるイベントハンドラを設定
		HttpClient.UploadStringCompleted += new UploadStringCompletedEventHandler(HttpPostCompleted);

		// POST 用 Http ヘッダの設定
		HttpClient.Headers["Content-Type"] = "application/x-www-form-urlencoded";

		string data_string = "send=send&text=" + Uri.EscapeDataString(value);
		HttpClient.UploadStringAsync(new Uri(url), "POST", data_string);

	}

	static void HttpPostCompleted(object sender, UploadStringCompletedEventArgs e)
	{
		if (e.Error == null)
		{
			MessageBox.Show("送信しました");
		}
		else
		{
			MessageBox.Show("通信エラーが発生しました。\r\n" + e.Error.Message);
		}
	}

}

関連する記事

PHP による『超簡易掲示板』 / アブリケーションからの POST 検証用


posted by lightbox at 2012-10-21 19:45 | Windows Phone | このブログの読者になる | 更新情報をチェックする

Json.NET を使って、XML データを JSON に変換して利用する / Windows Phone(C#)

using System.Xml.Linq が必要です。このサンプルでは、JObject を作成してループ処理していますが、実際は item 以下の JSON 文字列を作成して、JsonConvert.DeserializeObject を使って C# のクラスのインスタンスを作成します。

その クラスのインスタンスを DataContext に設定してバインドする事によって自動的に ListBox の表示が可能になります。
JObject RSS = null;
JArray jsonItems = null;
string json_string = null;
int rowMax = 0;

// XML 文字列を dom に変換
XDocument dom = XDocument.Parse(e.Result);

// dom を JSON 文字列に変換
json_string = JsonConvert.SerializeXNode(dom.FirstNode);

// JSON 文字列を JSON 表現可能な JObject に変換
RSS = JObject.Parse(json_string);

// 対象となる item の数を得る
jsonItems = (JArray)RSS["rss"]["channel"]["item"];
rowMax = jsonItems.Count;
// トップから一覧表示
for (int i = 0; i < rowMax; i++)
{
	Debug.WriteLine(RSS["rss"]["channel"]["item"][i]["title"]);
	Debug.WriteLine(RSS["rss"]["channel"]["item"][i]["description"]);
	Debug.WriteLine(RSS["rss"]["channel"]["item"][i]["link"]);
}

Debug.WriteLine("----------------------------------");

// 必要部分のみ(item)を JSON 文字列に戻す
json_string = JsonConvert.SerializeObject(jsonItems);
json_string = "{ item: " + json_string + "}";

RSS = JObject.Parse(json_string);

// 対象のみ
for (int i = 0; i < rowMax; i++)
{
	Debug.WriteLine(RSS["item"][i]["title"]);
	Debug.WriteLine(RSS["item"][i]["description"]);
	Debug.WriteLine(RSS["item"][i]["link"]);
}



タグ:JSON
posted by lightbox at 2012-10-21 01:36 | Windows Phone | このブログの読者になる | 更新情報をチェックする

2012年10月05日


Windows8 画像コントロール(Image) へファイルから表示する手順(C#)




1) FileOpenPicker オブジェクトを使って、目的のファイルに対応する StorageFile オブジェクトを作成
2) StorageFile オブジェクトの OpenAsync メソッドで目的のファイルに対するストリーム(random-access stream)を取得
3) BitmapImage オブジェクトSetSource メソッドでストリームを渡す
4) BitmapImage そのものを、Image コントロールの Source プロパティにセット

private async Task DisplayImageFileAsync(StorageFile file)
{
	// Request persisted access permissions to the file the user selected.
	// This allows the app to directly load the file in the future without relying on a
	// broker such as the file picker.
	m_fileToken = m_futureAccess.Add(file);

	// Display the image in the UI.
	BitmapImage src = new BitmapImage();
	src.SetSource(await file.OpenAsync(FileAccessMode.Read));
	Image1.Source = src;
	AutomationProperties.SetName(Image1, file.Name);

	// Use BitmapDecoder to attempt to read EXIF orientation and image dimensions.
	await GetImageInformationAsync(file);

	ExifOrientationTextblock.Text = Helpers.GetOrientationString(m_exifOrientation);
	UpdateImageDimensionsUI();

	ScaleSlider.IsEnabled = true;
	RotateLeftButton.IsEnabled = true;
	RotateRightButton.IsEnabled = true;
	SaveButton.IsEnabled = true;
	SaveAsButton.IsEnabled = true;
	CloseButton.IsEnabled = true;
}

▲ Microsoft の実際のサンプルコード
FileAccessMode enumeration



posted by lightbox at 2012-10-05 15:11 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

Windows8 の非同期処理(C#)

Windows8 の非同期処理は、イベント用のコールバックメソッドを用意するのでは無く、同期処理のようにソース行の記述と同じ順序で処理を実行する事ができます。その為に必要な記述方法として、await 演算子とasync キーワード が用意されています。



await 演算子を使うメソッドには、async キーワードでマークされた宣言が必要です。

非同期メソッドの戻り値の型は Task または Task<TResult> です。

最も外側のメソッドで try/catch ブロックを使うと、ネストされている非同期メソッドのエラーをキャッチできます(同期メソッドで例外をキャッチする方法と同様)。


Microsoft の解説ページ

非同期 API の呼び出し
FileOpenPicker.PickSingleFileAsync

// 呼び出し側
private async void Open_Click(object sender, RoutedEventArgs e)
{
	ResetPersistedState();
	ResetSessionState();

	try
	{
		rootPage.NotifyUser("Opening image file...", NotifyType.StatusMessage);

		StorageFile file = await Helpers.GetFileFromOpenPickerAsync();

		await DisplayImageFileAsync(file);

		rootPage.NotifyUser("Loaded file from picker: " + file.Name, NotifyType.StatusMessage);
	}
	catch (Exception err)
	{
		rootPage.NotifyUser("Error: " + err.Message, NotifyType.ErrorMessage);
		ResetSessionState();
		ResetPersistedState();
	}
}

// 非同期メソッド
public static async Task<StorageFile> GetFileFromOpenPickerAsync()
{
	// Attempt to ensure that the view is not snapped, otherwise the picker will not display.
	if (ApplicationView.Value == ApplicationViewState.Snapped && !ApplicationView.TryUnsnap())
	{
		throw new Exception("File picker cannot display in snapped view.");
	}

	FileOpenPicker picker = new FileOpenPicker();
	FillDecoderExtensions(picker.FileTypeFilter);
	picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
	StorageFile file = await picker.PickSingleFileAsync();

	if (file == null)
	{
		throw new Exception("User did not select a file.");
	}

	return file;
}

▲ サンプル全体はこちらから参照できます


posted by lightbox at 2012-10-05 13:52 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します


Windows
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり