Windows Mobile勉強会(id:n7shi:20101108)で使用した資料を公開します。
- 勉強会で発生した問題などを踏まえて、一部加筆修正しています。
VB.NETではmscorlibを差し替える設定が分からないため、同じ手法は使えません。- 【追記】コメントでVB.NET 2008での設定方法を教えていただきました。
- VC# 2008での方法、CABの作り方など ⇒ id:n7shi:20090106
- なぜこれで動くのかという資料 ⇒ id:n7shi:20091031
初期設定
VC# 2010でやっておくと便利な設定。
- ツール→設定→上級者設定
- ツール→オプション
- チェックする:すべての設定を表示
- テキストエディター→すべての言語→全般
- チェックする:行番号
描画が乱れる場合は以下の設定を推奨。(問題なければ不要)
- ツール→オプション→環境→全般
- チェックを外す:クライアントのパフォーマンスに基づいて視覚的効果を自動的に調整する
- チェックを外す:可能ならハードウェアのグラフィックスアクセラレータを使用する
プロジェクト作成
- プロジェクトファイルをエディタで開く
内の を以下のように書き換える
<ItemGroup> <Reference Include="mscorlib" /> <Reference Include="System" /> <Reference Include="System.Data" /> <Reference Include="System.Drawing" /> <Reference Include="System.Windows.Forms" /> <Reference Include="System.Xml" /> </ItemGroup>
- ソリューションを開く
- 実行してみる
- エラーが出てくるので、行ごと削除
- 実行できるようになる。
EXEをコピーすると端末で動くが、終了する手段がない。
[OK]で終了できるようにする。
WM 6.5.3ではメニューバーに[OK]が表示されるため、空メニューを作成。
Form1のコンストラクタに以下のコードを追加。
public Form1() { MinimizeBox = false; Menu = new MainMenu(); }
後は、GUIデザイナが使えない以外は、普通に開発できる。
普段はエミュレータなしで開発して、たまにエミュレータに転送して動作確認。
エミュレータ
動作が比較的軽くてインストールの依存関係も少ないWM6がお勧め。
- スタート→すべてのプログラム→Windows Mobile 6 SDK→Standalone Emulator Images→Japanese→Classic等
※ Windows 7ではショートカットが作成されない問題が何件も報告された。原因・対処法は不明。ショートカットは引数やカレントが複雑なので、EXEをクリックするだけでは起動しない。正常に作成された環境からショートカットをコピーして使うしかなさそう。
6.5.3のショートカットは独自に作成したものを提供中。しかし6.5.3は起動が重く、VGA等の解像度で表示が崩れる問題がある。
プロジェクトのDebugフォルダを共有しておくと、デバッグが簡単。
- ファイル→構成→全般→共有フォルダ
共有フォルダはエクスプローラでStorage Card扱いとなる。
表示しっぱなしにしておいて、デバッグしたいときにEXEをクリック。
動作がおかしくなったときはソフトリセットすると、起動後にコピーしたファイル等が消えなくて便利。
GUI
※この節のコードはすべてForm1クラス内に記述することが前提。
画面サイズ指定などの決まり文句を含めたテンプレートは以下の通り。
LayoutやAutoScale関係は自動調整のために必要。
public Form1() { Text = "アプリ"; Size = new Size(240, 320); MinimizeBox = false; SuspendLayout(); AutoScaleDimensions = new SizeF(96, 96); AutoScaleMode = AutoScaleMode.Dpi; Menu = new MainMenu(); InitializeComponent(); ResumeLayout(false); } private void InitializeComponent() { }
コントロール配置の定型。
buttonはInitializeComponent()以外でも使えるようにするため、外で定義。
button.Clickの行は、+=の部分で[+][=][Tab][Tab]と入力すれば簡単。
private Button button = new Button(); private void InitializeComponent() { button.Text = "ボタン"; button.Bounds = new Rectangle(10, 50, 100, 40); button.Click += new EventHandler(button_Click); Controls.Add(button); } void button_Click(object sender, EventArgs e) { MessageBox.Show("hello"); }
その他のコントロール
- Button, CheckBox, ComboBox, DateTimePicker, DomainUpDown, HScrollBar, Label, LinkLabel, ListBox, ListView, MonthCalendar, NumericUpDown, Panel, PictureBox, ProgressBar, RadioButton, Splitter, StatusBar, TabControl, TabPage, TextBox, ToolBar, TrackBar, TreeView, VScrollBar, WebBrowser
※ Windows 7では、Compact Frameworkで作成したTextBoxでIMEが使えないという問題が発生します。対処法は不明です。エミュレータや実機に転送すると問題なく入力できます。
描画
基本的なコード。
[O][V][Space][O][N][P][Enter]と入力すれば簡単。
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); using (var pen = new Pen(Color.Red)) using (var brush = new SolidBrush(Color.Blue)) { e.Graphics.DrawLine(pen, 0, 0, 20, 20); e.Graphics.DrawLine(pen, 0, 20, 20, 0); e.Graphics.FillRectangle(brush, 5, 5, 10, 10); e.Graphics.DrawString("abc", Font, brush, 0, 20); } }
EXEと同じフォルダの画像を読み込んで表示。
test.pngはプロジェクトにDnDして、プロパティでコピー設定しておく。
private Bitmap image; private void InitializeComponent() { var exe = Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName; var path = Path.GetDirectoryName(exe); var png = Path.Combine(path, "test.png"); image = new Bitmap(png); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.DrawImage(image, 5, 5); }
一定時間ごとに動かす(ちらつく)
※ダブルバッファは各自工夫してください!
private int x = 0; private void InitializeComponent() { var timer = new Timer(); timer.Interval = 50; timer.Tick += new EventHandler(timer_Tick); timer.Enabled = true; } void timer_Tick(object sender, EventArgs e) { x += 4; if (x >= ClientSize.Width) x = 0; Invalidate(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); using (var brush = new SolidBrush(Color.Red)) { e.Graphics.FillEllipse(brush, x, 0, 16, 16); } }
テクニック集
Mainに[STAThread]を指定できるようにする。
指定しないとOpenFileDialogなどが使えない。
namespace System { public class STAThreadAttribute : Attribute { } }
.NET 2.0でも拡張メソッドが使えるようにする。
namespace System.Runtime.CompilerServices { public class ExtensionAttribute : Attribute { } }
WMかどうかを判定して動作を変える。
if (Environment.OSVersion.Platform == PlatformID.WinCE) ...
EXEと同じフォルダのファイルにアクセス。
var exe = Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName;
var path = Path.GetDirectoryName(exe);
var ini = Path.Combine(path, "app.ini");
.NET 2.0では委譲型を定義しておくと便利。
namespace System { public delegate void Action(); public delegate void Action<T1, T2>(T1 a, T2 b); public delegate void Action<T1, T2, T3>(T1 a, T2 b, T3 c); public delegate TR Func<TR>(); public delegate TR Func<T1, TR>(T1 a); public delegate TR Func<T1, T2, TR>(T1 a, T2 b); }