WPF演習問題1 デスクトップ上のちり紙

読了目安:64分

20210920wpf241.png

気の早い人向け

20210923wpf417a1.png
(👆 2021年の現代で Windows専用の縛りがあって 誰が興味持つのか分からないが……)

20210922gif5.gif
(👆 この記事で 作れるもの)

📖 wpf-exercise-dust-paper-on-desktop - Git hub に上げたもの

今回の話し

ramen-tabero-futsu2-smartphone-size.png
「 Webアプリ15年ぐらい経験あるんで、 WPF? 応用で 簡単 簡単、と思って 面談通って 派遣入場したら WPF 思ってたやつと全然違った」

kifuwarabe-futsu-smartphone-size.png
「 お父んが 持ってないスキルだったもんな、 MVVM。 持ってないスキルで 派遣入場決めたの わらう」

ramen-tabero-futsu2-smartphone-size.png
「 座学退屈なんで 手を動かして 作りながら スキルを身に付けれるような 演習問題、わたしが欲しいのに無いんで 自分で作るぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 1990年代は プログラミング月刊雑誌 いっぱいあったのよ。 12か月購読すれば アプリケーションが1つ作れます、みたいな」

ramen-tabero-futsu2-smartphone-size.png
「 わたしが 無料で提供」

20210919wpf122.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Windows のアプリケーションを作るぞ! と思って 最初にやりたくなるのは Windows みたいな ウィンドウを消すことだと思うんだぜ」

kifuwarabe-futsu-smartphone-size.png
「 まだ ウィンドウも出したことないのに……」

ramen-tabero-futsu2-smartphone-size.png
「 👆 だから最初の演習問題 『デスクトップ上のちり紙』 では Windows みたいなウィンドウを消すことをやるぜ」

ramen-tabero-futsu2-smartphone-size.png
「 この演習問題の所要時間は、 どれぐらい初心者かにもよるが 集中すれば 土曜日1個消し飛ぶ程度で済むぐらいを想定」

ramen-tabero-futsu2-smartphone-size.png
「 この記事はどんどん転載したり、生配信したり コピー、加工しまくれだぜ
ただし 何も正しさは保証しないし この記事を元に何かして損害が起こっても責任は取らないぜ」

Step 1. Visual Studio 2022 導入

20210920wpf170-25per.png
📖 Visual Studio 2022 Preview をインストールしようぜ(^~^)?

ramen-tabero-futsu2-smartphone-size.png
「 👆 別記事を読んできてくれだぜ」

Step 2. 新規プロジェクト作成

ramen-tabero-futsu2-smartphone-size.png
「 おっ、 Visual Studio 2022 Preview Community のインストールは終わったかだぜ?」

20210920wpf156a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [新しいプロジェクトの作成(N)] をクリックするか、 [Alt] + [N] キーを打鍵するかしろだぜ」

Step 2-1. アクセラレーター キー

20210925wpf472a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 メニューや、ボタンの名前の後ろに 丸かっこに入って アンダースコア(下線)が引かれている英字大文字は
古い言い方で ニーモニック(mnemonic)、 一般的には アクセラレーター キー(Accelerator keys) と呼ぶもので、
[Alt] キーを押しながら そのアルファベットのキーを ちょんと押すと クリックしたのと同じ動きをするぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 Web系では 無くなった文化よね」

20210925wpf476a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Alt] というのは オルタネート キー(Alternate key) とか オルト と呼んでるもので、
このキーを押したからといって 何かが起こるわけではないが、別のキーと組み合わせて使うぜ」

20210925wpf477.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Alt] + [N] キーと言う場合、 オルト キーと N キーを 一緒に押すのではなく……」

20210925wpf478.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Alt] キーを押しっぱなしにしながら、 [N] キーを ちょん と押し下げて すぐ 離せだぜ」

kifuwarabe-futsu-smartphone-size.png
「 こだわりだな」

ohkina-hiyoko-futsu2-smartphone-size.png
「 大阪日本橋の近くに住んでたから こういうことを 一通り教えてくれる コンピューター オタク の先輩が近所にいたけど、
それは 特異 なことで、世の中 そんな人は 近所にはいないのよ 。
世間の人は ネットの切れ端みたいな記事みて プログラムを 断片的に覚えるのよ。
その構造に うらみの根を持って こういう一気通貫の 長い 記事かいてんのよ」

kifuwarabe-futsu-smartphone-size.png
「 逆恨み わらう」

20210920wpf157a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 C#すべてのプラットフォームデスクトップWPF Application をクリックして [次へ(N)] をクリックしろだぜ。
ここで、 .NET Framework と付いてあるのは レガシー(時代遅れ)なんで選ぶなだぜ。付いてないのを選べだぜ」

kifuwarabe-futsu-smartphone-size.png
「 ややこし!」

20210925wpf473a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 次の画面にも アクセラレーター キー いっぱいついてるな」

20210925wpf474a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 3点リーダーは ダイアログボックスが ポップアップしてくる印だぜ」

Step 2-2. フォーカス

20210925wpf475a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 また、テキストボックスに これから文字を入力しようというとき、テキストボックスは フォーカス(Focus) を持っていると言うぜ」

Step 2-3. タブ オーダー

20210925gif6.gif

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Tab] キーを打鍵すると、フォーカスは 次の クリックできるところへ飛ぶぜ。 これを特に専門用語は無いが、 タブ オーダー(Tab Order) とか呼ぶぜ」

20210925gif7.gif

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Shift] - [Tab] キーを打鍵すると 逆回りだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 タブ オーダーは Web系にもあるわねぇ」

20210920wpf158a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [プロジェクト名] は WpfExerciseDustPaperOnDesktop にでもしろだぜ。
[場所] はデフォルトのままでもいい。わたしは C\GitHub というフォルダーを作って そこに置いてるけど」

20210920wpf159.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 わたしも知らんけど 今年の11月ぐらいには出てくるらしい .NET 6.0(プレビュー) にしよかな」

20210920wpf160.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 開発画面が出てきたぜ。 前の Visual Studio 2019 とパッと見た感じ 変わってない感じ」

20210920wpf161a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 プロジェクト名を後で変えたくなったときは、 右上の ソリューション エクスプローラーの ツリー構造の2段目を右クリックして
[名前の変更(M)] を選ぶか、または [F2] キーを打鍵すれば変更できるんだが……」

20210925wpf479.png

kifuwarabe-futsu-smartphone-size.png
「 👆 [F2] は ファンクション キー(Function Key) だな」

ramen-tabero-futsu2-smartphone-size.png
「 ファンクション キーも 本来は 好きに使っていい ショートカットのためのキー だったと思うんだが、
Windows になると F1 は ヘルプだとか F2 は名前変えるだとか、 使い方が固定されてきた」

ramen-tabero-futsu2-smartphone-size.png
「 慣習を引き継ぐのは 古い世代に任せて、 いち から コンピューターはどうあるべきか 今の文化を 見直そう、という動きがあっても いいと思ったら
デスクトップPC 丸ごと無視して みな スマホ の方に行ってしまった」

ohkina-hiyoko-futsu2-smartphone-size.png
「 現代日本は スマホ先進国かも」

20210920wpf160a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 自動で変更してくれない 残り が どこかにあったりするんで、
詳しくないうちは プロジェクト名を付け間違えたら 最初からやり直せだぜ」

Step 3. NuGetでLivet インストール

ramen-tabero-futsu2-smartphone-size.png
「 👇 WPF を開発するのに 何かフレームワークを入れておかないと ぜんぜんできないんで、フレームワークは Livet を選ぶぜ」

20210920wpf162a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [ツール] - [NuGet パッケージ マネージャー] - [ソリューション NuGet パッケージの管理] をクリックしろだぜ」

20210920wpf163a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [参照] タブをクリックして検索ボックスに Livet と打鍵し、 LivetCask を選んで プロジェクトの横のチェックボックスをクリックして インストール しろだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 インストールが終わったら NuGet のページは閉じろだぜ」

Step 4. 画面見やすいように整えろ

20210920wpf164.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 今 こんな感じの画面かも知れないな。
このままでは 使いにくいかも知れないから……」

20210920wpf171-25per.png
📖 WPF開発してるときの、画面の整え方をまとめようぜ(^~^)

ramen-tabero-futsu2-smartphone-size.png
「 👆 画面を整える方法を まとめたんで 上の記事を読めだぜ」

Step 5. 定番のフォルダー作れ

20210920wpf184a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ソリューション エクスプローラーの2つ目ぐらいにある プロジェクトを右クリック、
[追加] - [新しいフォルダー] をクリックしろだぜ」

20210920wpf185a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 名前を入れろだぜ。
ここでは ViewModelsViews という名前の2つのフォルダーを作れだぜ」

20210920wpf186a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 名前を入れ間違えたら、 [F2] キーを打鍵すれば リネームできるぜ」

Step 6. 実行しろ

ramen-tabero-futsu2-smartphone-size.png
「 まだ何もプログラム書いてないが、最初から ウィンドウを表示するぐらいのことはできる。やってみようぜ」

20210920wpf187a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 標準ツールバーの 右向いてる緑色の三角形みたいなボタンをクリックしてみろだぜ」

20210920wpf188.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Visual Studio のウィンドウのレイアウトが がらりと変わって、 なんか 白いウィンドウが出てきただろ。
じゃ、その 出てきた白いウィンドウを 閉じろだぜ」

20210920wpf189a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ソリューション エクスプローラーの プロジェクト名を右クリックして エクスプローラーでフォルダーを開く をクリック」

20210920wpf190a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Windows ファイル エクスプローラー が出てくるので、 bin フォルダーの中を開けていけだぜ」

20210920wpf191a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 .exe ファイルができてるから、ダブルクリックしろだぜ」

20210920wpf192.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 じゃあ さっきの 白いウィンドウが出てきたな。 これが 実行ファイル の作り方の基本だぜ」

Step 6. タイトル バー消せ

20210920wpf200a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ソリューション エクスプローラー上で MainWindow.xaml をダブルクリックしろだぜ。
デザイナーが出てくるな」

20210920wpf201a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 XAML の方の <Window という要素名を狙って マウスカーソルでクリックしろだぜ。
プロパティが出てくるな」

20210920wpf202a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 プロパティ ペーンの [雷マーク] - [カテゴリ] - [外観] - [WindowStyleのドロップダウンリストの三角ボタン] - [None] を選べだぜ」

20210920wpf203a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すると XAML の方に WindowStyle="None" が付いたな」

20210920wpf203a3.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 こんな感じに覚えておけだぜ。
プロパティ ペーンで設定したものは XAML のタグのアトリビュートに付く、ぐらいの規則性に気づけだぜ。
アトリビュートに どんな風に付くかは、なんかシンプルに付くと思っておけだぜ、今のところは」

ohkina-hiyoko-futsu2-smartphone-size.png
「 慣れてきたら XAML のテキストを直接 編集しろってことなのかしら」

ramen-tabero-futsu2-smartphone-size.png
「 XAMLはテキストなんで、コピー 貼り付け も利くしな。規則性の分かってきたプログラマーは XAML 直接編集だよな」

Step 7. XMLの 単独タグ

kifuwarabe-futsu-smartphone-size.png
「 このステップの話しは むずかしいんで、 読み飛ばして 構わないぜ。必要になったら読めばいい」

ramen-tabero-futsu2-smartphone-size.png
「 XML(エックス・エム・エル)の読み方を簡単に説明するぜ」

20210925wpf508a1.png

ramen-tabero-futsu2-smartphone-size.png
「 <> で挟まれたものを タグ と呼んでいるのは分かると思うが、うしろの括弧に / (スラッシュ)が付いている /> を持つものは、
なんか 単独なんだな、と思っておけだぜ」

Step 7-1. 開きタグ、閉じタグ

20210925wpf508a2.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 要素 (Element;エレメント) は 開きタグ閉じタグ で作れるやつもあるぜ。
どう使い分けるのかというと……」

Step 7-2. 子要素、親要素

20210925wpf508a3.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 閉じタグ、開きタグに分かれている方は、間に 子要素 などを挟めるわけだぜ。
何も挟まない要素は 単独タグ が使いやすいぜ」

Step 7-3. アトリビュート

20210925wpf508a4.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 また 単独タグ、または 開きタグは、 属性名="属性値" という形で 名前と値(Value;あたい)のペアを持てるぜ。
これを アトリビュート(属性;ぞくせい)と呼ぶぜ」

20210925wpf508a5.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 アトリビュートは 複数個 付けれるぜ」

Step 7-4. テキスト ノード

20210925wpf508a6.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 開きタグ と 閉じタグの間に テキスト をそのまま書いてもOKだぜ」

Step 8. XAML プロパティ要素構文

kifuwarabe-futsu-smartphone-size.png
「 このステップの話しは むずかしいんで、 読み飛ばして 構わないぜ。必要になったら読めばいい」

📖 XAML 構文のガイド

ramen-tabero-futsu2-smartphone-size.png
「 👆 XAML(ザムル)は、 XML に追加ルールを設けたものだぜ。簡単に説明するぜ」

20210925wpf508a7.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 XML では、 アトリビュートの値に 要素を入れる、みたいなことはできず、
&lt;FullName&gt;なんとか と 三角形の括弧を エスケープ して入れるぐらいだったんだが、 XAML では そこは……」

20210925wpf508a8.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 こんな書き方で アトリビュートに要素を入れるのを許容しよう、という 運用 をしてるわけだぜ。
なるほど 確かに XML の表現力が 爆上げ してるぜ。歓迎だぜ」

Step 8-1. 添付プロパティ

20210925wpf508a9.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 上図の Game.Series プロパティは、 Character要素のプロパティではなくて、
親要素の Game のプロパティを使ってる、みたいな 書き方も XMLに追加ルールで運用される。
これも 今は便利さが分からないと思うが、使いようがあって、 XML の表現力が 爆上げ してるぜ。歓迎だぜ」

Step 9. ファイル保存しろ

20210920wpf203a4.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ここで!
タブに書いてある ファイル名の末尾に注目してくれだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 えっ? どこ!」

20210920wpf203a5.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ここ!」

ohkina-hiyoko-futsu2-smartphone-size.png
「 なんか 人型が付いてるかなあ?」

ramen-tabero-futsu2-smartphone-size.png
「 * (アスタリスク)だぜ。
ファイル名のうしろに * が付いているファイルは、まだ保存されていません、という印だぜ」

20210920wpf242.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すべて保存 ボタンをクリックして すべてのファイルを保存するか……」

ramen-tabero-futsu2-smartphone-size.png
「 [Ctrl] キーと [Shift] キーを押しっぱなしにしながら [S] キーを ちょんと 軽く打鍵しろだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 これを [Ctrl] + [Shift] + [S] とコマンド表記することがあるぜ。
3つのキーを 同時押し しようとすると プログラムに s の字を書きこんで できねーっ てなるんで、
[Ctrl][Shift][Alt] キーは 他のキーと一緒に押さなければ (基本的に) 何も起こらないようになってるんだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 Shiftキーを5連打してみなさいよ。 びっくりして 椅子から転げ落ちるから」

20210920wpf243.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ファイルを1つ保存するボタンをクリックして アクティブなファイルを……、アクティブなファイルって何かって説明するのが難しいよな。
今 キーボードの a を押したら a の字が打ち込まれるようなテキスト・ファイルとかのことだぜ。
アクティブなファイルだけ 保存されるぜ」

ramen-tabero-futsu2-smartphone-size.png
「 代わりに [Ctrl] + [S] キーでも保存できるぜ」

ramen-tabero-futsu2-smartphone-size.png
「 あっ、 2021年にもなって フロッピー ディスク💾 のアイコンだぜ!」

Step 9-1. 実行して確認

20210920wpf203a6.png

kifuwarabe-futsu-smartphone-size.png
「 デザイナー見ても 見た目は何も変わってないけどな」

ramen-tabero-futsu2-smartphone-size.png
「 実行してみろだぜ」

20210920wpf204.png

kifuwarabe-futsu-smartphone-size.png
「 👆 何か変わったかだぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 タイトルバーが消えたぜ。 あと もともと見えてないが ウィンドウの枠が消えたぜ。
昔は ウィンドウに 太い枠が有ったんだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 残っている部分は クライアント領域 と呼ぶぜ。 変な名前だが、
Windows ME ぐらいの頃から クライアント領域 って呼んでたから ずっと昔から クライアント領域って名前なんだぜ」

Step 9-2. ウィンドウの閉じ方

20210920wpf209a1.png
(👆 閉じるボタンが無くなったときの ウィンドウの閉じ方)

ramen-tabero-futsu2-smartphone-size.png
「 👆 閉じるボタン 無くなっちゃったんで、タスク バーのアイコンを右クリックして ウィンドウを閉じる を選んでくれだぜ」

Step 10. クライアント領域、透明

ohkina-hiyoko-futsu2-smartphone-size.png
「 クライアント領域が 透明になってほしいのよ」

20210920wpf205a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 プロパティ ペーンで AllowsTransparency にチェックを入れろだぜ」

20210920wpf206a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ブラシ カテゴリの Background#00000000 を入れろだぜ。 #00xxxxxx
不透明度(Opacity)あるいはアルファ値が 00、つまり 透明という意味だぜ」

20210920wpf207.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ほら クライアント領域が透明になったぜ。
なんか 1 pixel ぐらいの黒い枠線が残ってんな……」

kifuwarabe-futsu-smartphone-size.png
「 実行してみると 黒い線も見えないぜ。 透明で、どこにあるかも見えないウィンドウだぜ」

20210920wpf208a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ウィンドウのリサイズ用の境界線かも知らん。 ResizeMode="NoResize" を付けてくれだぜ」

kifuwarabe-futsu-smartphone-size.png
「 デバッグ実行時に 1 pixel の黒い枠線は見えるぜ。何も変わらないぜ」

ramen-tabero-futsu2-smartphone-size.png
「 じゃあ ResizeMode 関係ないのか」

Step 11. 丸とか四角、置け

ramen-tabero-futsu2-smartphone-size.png
「 グリッド デザインは 初心者には早かったのでは……、まあいいか やったろ」

20210920wpf212-25per.png
📖 WPFのGridとかStackPanelとかWrapPanelって何なんだぜ(^~^)?

ramen-tabero-futsu2-smartphone-size.png
「 👆 グリッドって何か、の説明は 上の記事を読んできてくれだぜ」

20210920wpf213a1.png

MainWindow.xaml:

<Window x:Class="WpfVisualStudio2022Practice.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfVisualStudio2022Practice"
        mc:Ignorable="d"
        Title="MainWindow" Width="300" Height="300" WindowStyle="None"
        AllowsTransparency="True" Background="#00000000">

    <!--
        くしゃくしゃになった ちり紙 を表現したいですが、
        大変なので 正方形2つ、丸1つを描画します
    -->
    <Grid>
        <!-- 2行2列のグリッド -->
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <!-- 左上に四角 -->
        <Rectangle Width="140" Height="140" Fill="WhiteSmoke"/>

        <!-- 右上に丸 -->
        <Ellipse Grid.Column="1" Width="140" Height="140" Fill="PapayaWhip"/>

        <!-- 下段に長方形 -->
        <Rectangle Grid.Row="1" Grid.ColumnSpan="2" Width="200" Height="140"
                   Fill="AliceBlue"/>

    </Grid>

</Window>

ramen-tabero-futsu2-smartphone-size.png
「 👆 XAML をコピー貼り付けするだけで 丸とか 四角とか置けるから 試してくれだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 マウスカーソルで テキストを選んで [Ctrl] + [C]
貼り付けたいところに [Ctrl] + [V] で貼り付け」

Step 12. テキスト、置け

ramen-tabero-futsu2-smartphone-size.png
「 Web系プログラマーでなければ 知らないから関係ないもしれないが、
HTML だと タグの中にタグを入れて、またその中にタグを入れて…… と
入れ子が激しいんだが、WPFの グリッド レイアウトだと 入れ子は 少し緩和されるぜ」

20210920wpf214a1.png

        <!-- ちらしっぽいメッセージを書きましょう -->
        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
                   TextAlignment="Center" FontSize="20" IsHitTestVisible="False">
            ここに<LineBreak/>
            紙を貼るな!</TextBlock>
        <TextBlock Grid.Column="1"
                   HorizontalAlignment="Center" VerticalAlignment="Center"
                   TextAlignment="Center" FontSize="20" IsHitTestVisible="False">
            へ へ<LineBreak/>
            の の<LineBreak/>
            も<LineBreak/>
            へ</TextBlock>
        <StackPanel Grid.Row="1" Grid.ColumnSpan="2" Width="200" Height="140"
                    IsHitTestVisible="False">
            <TextBlock FontSize="20" Text="6 + 7 = 15" TextDecorations="Strikethrough"/>
            <TextBlock FontSize="20">6 + 7 = 13<LineBreak/>
                13 + 3 = 16</TextBlock>
        </StackPanel>

ramen-tabero-futsu2-smartphone-size.png
「 👆 XAML をコピー貼り付けするだけで テキストを置けるから 試してくれだぜ」

Step 13. ボタン、置け

kifuwarabe-futsu-smartphone-size.png
「 タイトルバーがなくなったんで
ウィンドウをつかむところがなくなって ウィンドウを移動できなくなったし、
ウィンドウの枠がなくなったんで ウィンドウの端っこをつかんで リサイズできなくなったし、
最小化、最大化、閉じるボタンも無くなったんで、
これら 自力実装しなくちゃ いけないな」

ohkina-hiyoko-futsu2-smartphone-size.png
「 黙って Windows のルックスをそのまま使って 生産性の向上 に注力したらいいのに」

ramen-tabero-futsu2-smartphone-size.png
「 最初の この演習は、
ウィンドウに最初から付いているものを 消して、 自力で再実装することだぜ」

kifuwarabe-futsu-smartphone-size.png
「 苦行わらう」

20210919wpf123a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 まず、押しても何も起こらないボタン を置こうぜ?」

20210920wpf215a1.png

        <!-- ここにボタンを並べてください -->
        <Grid Grid.Row="1" Grid.ColumnSpan="2" Width="240" Height="140">
            <!-- 2行0列のグリッド -->
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <!-- 0行目は空きスペース -->
            <!-- 1行目 ここにボタンを並べてください -->
            <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
                <Button Width="40" Height="30" Content="最小"/>

                <!-- 元のサイズに戻すボタンです -->
                <Button Width="80" Height="30" Content="元サイズ戻す">
                </Button>

                <!-- ウィンドウを最大化するボタンです -->
                <Button Width="40" Height="30" Content="最大">
                </Button>

                <!-- 閉じるボタンです -->
                <Button Width="40" Height="30" Content="閉じ"/>
            </StackPanel>
        </Grid>

ramen-tabero-futsu2-smartphone-size.png
「 👆 XAML をコピー貼り付けするだけで ボタンを置けるから 試してくれだぜ」

20210920wpf216.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 まだ 張りぼて だな」

Step 14. ボタンに機能付けろ

ramen-tabero-futsu2-smartphone-size.png
「 最大化したときの見え方とか、テストしたいだろ。
ボタンに機能が入ってないと不便だよな。付けようぜ?」

20210920wpf217a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 デザイナーで 最小ボタンをクリック、 プロパティ ペーンで 雷マーク をクリックして Click の右横のテキストボックスを
ダブルクリックしろだぜ。 最小ボタンをダブルクリックしても同じだけど」

20210920wpf218a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 コードの画面に飛ぶぜ。 Button_Click とか書かれたコードができているが、これが スケルトン だぜ。
スケルトンというのは、 ここにコードを書け っていう 中身が空っぽなものだぜ」

Step 14-1. 保存しろ

ramen-tabero-futsu2-smartphone-size.png
「 思い出せだぜ」

20210920wpf219a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ファイル名のうしろに * (アスタリスク)が付いているのは、まだ 保存されていないという印だぜ」

20210920wpf220.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すべて保存 ボタンをクリックするか、 [Ctrl] + [Shift] + [S] キーをクリックしろだぜ。
保存されてないファイル全部保存されるぜ。
ファイルを1つずつ保存したいときは [Ctrl] + [S] だぜ。まあ試せ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 特に 2000年 '00年代のデジタルなイラストレーターは 保存 ボタン押し忘れて 1日の作業が消えるし、
特に '00年代のデジタルなイラストレーターは ハードディスクのバックアップを取ってないから 生涯の全作品が消えるのよ」

kifuwarabe-futsu-smartphone-size.png
「 2020年代になると いい感じの企業の会社員は どこかにある データセンターのサーバーに ログインしてから作業するんで
データは サーバー側のディスクに取ってるよな。 会社がバックアップを取ってくれてるぜ。
目の前にある 貸与のローカルPCにデータ置いてないよな」

Step 15. メソッド名 変更

ramen-tabero-futsu2-smartphone-size.png
「 メソッドって何なのか、という説明は置いておいて」

20210920wpf221a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Button_Click のところで右クリックして、 名前の変更 を選んでくれだぜ」

20210920wpf222a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 MinimizedButton_Click に変えて [Enter] キーを打鍵(だけん;タップ)してくれだぜ」

20210920wpf223a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すると 名前が変わるのは もちろん だが」

20210920wpf224a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 参照箇所も併せて変わってくれるので 修正の手間要らずだぜ」

20210920wpf225a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 以下同様で、 MinimizedButton_ClickNormalButton_ClickMaximizedButton_ClickCloseButton_Click
4つのスケルトンを用意してくれだぜ」

20210919wpf124a1.png

        private void MinimizedButton_Click(object sender, RoutedEventArgs e)
        {
            // ウィンドウを最小化します
            this.WindowState = WindowState.Minimized;
        }

        private void NormalButton_Click(object sender, RoutedEventArgs e)
        {
            // 最大化しているウィンドウを元に戻します
            this.WindowState = WindowState.Normal;
        }

        private void MaximizedButton_Click(object sender, RoutedEventArgs e)
        {
            // ウィンドウを最大化します
            this.WindowState = WindowState.Maximized;
        }

        private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            // このウィンドウを閉じます
            this.Close();
        }

ramen-tabero-futsu2-smartphone-size.png
「 👆 それぞれの機能は 1行呼び出せば済むぜ」

Step 15-1. 最大化を試せ

20210924wpf445a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 実行してみろだぜ」

20210924wpf446a1.png

ramen-tabero-futsu2-smartphone-size.png
「 ちり紙の [最大] ボタンをクリックしてみろだぜ」

20210924wpf447.png

kifuwarabe-futsu-smartphone-size.png
「 👆 広がったぜ」

Step 16. 可視/不可視、活性/非活性

20210920wpf228a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すでに 最大化 してるんだったら [最大化] ボタンなんか見えない方がいいし……」

20210920wpf229a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すでに 元のサイズに戻っているのなら、元のサイズに戻すボタンなんか見えない方がいいぜ」

ramen-tabero-futsu2-smartphone-size.png
「 プログラマーが意識したいのは
機能があるものは、その機能を持っているように見えること、
機能をもっていないものは、その機能をもっていないように見えること、
機能を持っているように見えるものは、その機能を持っていること、
機能を持っていないように見えるものは、その機能を持っていないこと だぜ」

kifuwarabe-futsu-smartphone-size.png
「 逆も真か」

ohkina-hiyoko-futsu2-smartphone-size.png
「 対偶だから 最後の2行は要らなくない?」

kifuwarabe-futsu-smartphone-size.png
「 通常のサイズのとき 元のサイズに戻すボタンを 見えなくして、
最大化のサイズのときは 最大化ボタンを 見えなくしてくれだぜ」

Step 17. テンプレート(良くない例)

ramen-tabero-futsu2-smartphone-size.png
「 じゃあ まず 良くない書き方の例から説明するぜ。
そのあとで 良い書き方の例を説明する」

20210920wpf230a1.png

                <!-- 元のサイズに戻すボタンです -->
                <Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click">
                </Button>

ramen-tabero-futsu2-smartphone-size.png
「 👆 今、ボタンは シンプルに書けてるんだが、これを 複雑に書いていってみるぜ。お見せしよう」

20210920wpf231.png

                <!-- 元のサイズに戻すボタンです -->
                <Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click">
                    <Button.Template>
                        <ControlTemplate TargetType="Button">

                        </ControlTemplate>
                    </Button.Template>
                </Button>

ramen-tabero-futsu2-smartphone-size.png
「 👆 Button が Template というプロパティを持っているんで、そこに ControlTemplate をセットするには、
上記みたいな書き方をするのが一番簡単なんだが、この書き方は XAML が読みにくくなるんだぜ。続けるぜ」

20210921wpf249a1.png

                <!-- 元のサイズに戻すボタンです -->
                <Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click">
                    <Button.Template>
                        <ControlTemplate TargetType="Button">

                            <!-- ニュートラル状態でのボタンのルックスです -->
                            <Grid>
                                <Rectangle Width="80" Height="30"
                                           Stroke="#FF000000" StrokeThickness="0.5"
                                           Fill="#FFDDDDDD"/>
                                <Label Content="元サイズ戻す"/>
                            </Grid>

                            <ControlTemplate.Triggers>
                                <!-- ウィンドウのサイズがニュートラルな状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Normal">
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                </DataTrigger>
                            </ControlTemplate.Triggers>

                        </ControlTemplate>
                    </Button.Template>
                </Button>

ramen-tabero-futsu2-smartphone-size.png
「 👆 ニュートラルな状態での 元のサイズに戻す ボタンと、
ウィンドウのサイズが ニュートラル なときの 元のサイズに戻す ボタンの場所を無くす設定だぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 すっきりしてた XAML が、とたんに ごちゃごちゃ し出したわねぇ」

20210920wpf233a1.png

kifuwarabe-futsu-smartphone-size.png
「 確かに 普通のサイズに戻す ボタンは 場所が無くなってるぜ」

Step 18. テンプレート(良い例)

ramen-tabero-futsu2-smartphone-size.png
「 そこで リソース ディクショナリー を使うやり方を、初心者こそ 早く覚えようぜ」

20210920wpf234a1.png

MainWindow.xaml:

    <!-- このウィンドウでだけ使うリソースを定義します -->
    <Window.Resources>

    </Window.Resources>

ramen-tabero-futsu2-smartphone-size.png
「 👆 Window要素の冒頭らへんに <Window.Resources> 子要素を置こうぜ」

20210921wpf245.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 そして さっきの <ControlTemplate> 要素を カット&ペースト」

20210921wpf246a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 上図の位置で k を入力して 候補から Key (x) を選択」

20210921wpf247a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 " (ダブルクォーテーション )の閉じるとこまで 自動で補完してくれるから、その中を書けばいいんだが、
ここに何を書くかというと まあ 先頭が小文字英字 の例が多いぐらいで 任意(にんい)の名前だぜ」

kifuwarabe-futsu-smartphone-size.png
「 にんい って何だぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 勝手にしろ、ぐらいの意味だぜ」

20210921wpf248a1.png

    <!-- このウィンドウでだけ使うリソースを定義します -->
    <Window.Resources>
        <ControlTemplate x:Key="normalButton" TargetType="Button">

            <!-- ニュートラル状態でのボタンのルックスです -->
            <Grid>
                <Rectangle Width="80" Height="30"
                                           Stroke="#FF000000" StrokeThickness="0.5"
                                           Fill="#FFDDDDDD"/>
                <Label Content="元サイズ戻す"/>
            </Grid>

            <ControlTemplate.Triggers>
                <!-- ウィンドウのサイズがニュートラルな状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Normal">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </ControlTemplate.Triggers>

        </ControlTemplate>
    </Window.Resources>

ramen-tabero-futsu2-smartphone-size.png
「 👆 キーの値は normalButton とかにしとこうぜ」

20210920wpf238a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 切り取った方を どうするかというと」

20210920wpf239a1.png

Template="{StaticResource }"

ramen-tabero-futsu2-smartphone-size.png
「 👆 上記みたいな感じで キータイピングしていると 入力候補が出てくるんで、 onrmalButton を選べだぜ。
入力候補出ないな? と思ったら [Ctrl] + [Space] キーを打鍵(だけん;タップ)しろだぜ」

20210920wpf240a1.png

                <!-- 元のサイズに戻すボタンです -->
                <Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click"
                        Template="{StaticResource normalButton}"/>

ramen-tabero-futsu2-smartphone-size.png
「 👆 これで さっきと同じ働きもするし、 XAMLも読みやすい 良い書き方だぜ」

kifuwarabe-futsu-smartphone-size.png
「 コーディングの初心者のときに コーディング スキルの高い技を持っていたいよな」

ohkina-hiyoko-futsu2-smartphone-size.png
「 低いコーディング スキルと、ものすごい熱意で 重量級のコード書くのも 誰もが通るところだから それはそれで構わないのよ。
それを引き継ぐことになって メンテナンスするのも 構わないのよ。
飛伝のタレで メンテナンスしてはいけなくなって 継承を続けることが伝統になるのが 嫌なだけで」

Step 18-1. 最大化ボタンも同様

        <ControlTemplate x:Key="maximizedButton" TargetType="Button">

            <!-- ニュートラル状態でのボタンのルックスです -->
            <Grid>
                <Rectangle Width="40" Height="30"
                           Stroke="#FF000000" StrokeThickness="0.5"
                           Fill="#FFDDDDDD"/>
                <Label Content="最大"/>
            </Grid>

            <ControlTemplate.Triggers>
                <!-- ウィンドウのサイズが最大の状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Maximized">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </ControlTemplate.Triggers>

        </ControlTemplate>
                <!-- ウィンドウを最大化するボタンです -->
                <Button Width="40" Height="30" Content="最大" Click="MaximizedButton_Click"
                        Template="{StaticResource maximizedButton}"/>

Step 19. テンプレートバインディング

kifuwarabe-futsu-smartphone-size.png
「 しかし お父ん」

20210921wpf250a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 Button タグには Widh="80" とか Content="元サイズ戻す" といったアトリビュートが残っているな?」

ramen-tabero-futsu2-smartphone-size.png
「 残っているぜ」

20210921wpf251a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ControlTemplate タグの方にも、 Widh="80" とか Content="元サイズ戻す" とか、おんなじ値のアトリビュートがあるな?」

ramen-tabero-futsu2-smartphone-size.png
「 あるぜ」

20210921wpf253.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ButtonWidth="80" と、 ControlTemplateWidh="80" だったら、どっちを使ってるんだぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 Button の方は無視して ControlTemplate の方を使ってるぜ」

ramen-tabero-futsu2-smartphone-size.png
「 ControlTemplate が ぶら下がったら、元のタグの方のレイアウトは すっかり忘れてしまって
ごっそり ControlTemplateの方が使われると思えだぜ」

kifuwarabe-futsu-smartphone-size.png
「 じゃあ Button の方の Width="80" とかは使ってないんだったら 消したらいいんじゃないか?」

ramen-tabero-futsu2-smartphone-size.png
「 どっちかと言うと…… ControlTemplate の方の Width="80" を消したいんだぜ。
ButtonWidth="80" と指定したら、 ControlTemplate の方の Width も 80 になってほしい」

20210921wpf254a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ControlTemplate って名前をしているが、こういうの テンプレート (Template) という概念なんだぜ。
テンプレートって何かというと 穴あき定規 なんだが」

ohkina-hiyoko-futsu2-smartphone-size.png
「 穴定規がどうしたっていうの」

ramen-tabero-futsu2-smartphone-size.png
「 おんなじ物 何回も使う、っていうことだぜ。
そのとき 一部分だけ ちょっと変えて使いたい なんてことも よくあるわけだぜ」

20210921wpf255a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Width=" の始まりのダブルクォーテーションのすぐ右から {B と打鍵し始めろだぜ。
インテリセンス(IntelliSense)が出てくる……、この入力候補が出てくるやつのこと インテリセンスとか呼んでるやついるのかだぜ?」

kifuwarabe-futsu-smartphone-size.png
「 候補だよな。あるいは サジェスチョン」

ramen-tabero-futsu2-smartphone-size.png
「 Visual Studio は インテリセンス が出てくるのが自慢なんで、 Visual Studio を使うんだったら積極的にインテリセンスを使えだぜ。
なんなら [Ctrl] + [Space] で こっちから インテリセンスを呼び出せるぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 わらう」

ramen-tabero-futsu2-smartphone-size.png
「 Bind とか打鍵すれば そこで書ける バインドの種類が一覧されるんで、 TemplateBinding を選べだぜ。
テンプレートで使うバインディングだから TemplateBinding なんだろ、簡単だろ」

kifuwarabe-futsu-smartphone-size.png
「 何なんだぜ それ」

20210921wpf256a1.png

ramen-tabero-futsu2-smartphone-size.png
「 そして 半角スペース1個空ければ また インテリセンスが出てくるぜ。
これは テンプレートのタグに TargetType="Button" って書いてるから Button と知ってて出てくるんだけど」

20210921wpf257a1.png

ramen-tabero-futsu2-smartphone-size.png
「 さらに W って打てだぜ。 Width (ウィトゥス;横幅)が出てくるぜ。
これ、 Button の Width だぜ」

20210921wpf258a1.png

                <Rectangle Width="{TemplateBinding Width}" Height="30"
                           Stroke="#FF000000" StrokeThickness="0.5"
                           Fill="#FFDDDDDD"/>

ramen-tabero-futsu2-smartphone-size.png
「 👆 これで ControlTemplate から Width="80" が消えて、 Button の方の Width="80" になったんだぜ。
これが バインディング」

kifuwarabe-futsu-smartphone-size.png
「 他のところも バインディング してしまおうぜ?」

20210921wpf259.png

    <!-- このウィンドウでだけ使うリソースを定義します -->
    <Window.Resources>

        <!-- ウィンドウを元のサイズに戻すボタンです -->
        <ControlTemplate x:Key="normalButton" TargetType="Button">

            <!-- ニュートラル状態でのボタンのルックスです -->
            <Grid>
                <Rectangle Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
                           Stroke="{TemplateBinding Foreground}" StrokeThickness="0.5"
                           Fill="{TemplateBinding Background}"/>
                <Label Content="{TemplateBinding Content}"/>
            </Grid>

            <ControlTemplate.Triggers>
                <!-- ウィンドウのサイズがニュートラルな状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Normal">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </ControlTemplate.Triggers>

        </ControlTemplate>

        <!-- ウィンドウを最大化するボタンです -->
        <ControlTemplate x:Key="maximizedButton" TargetType="Button">

            <!-- ニュートラル状態でのボタンのルックスです -->
            <Grid>
                <Rectangle Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
                           Stroke="{TemplateBinding Foreground}" StrokeThickness="0.5"
                           Fill="{TemplateBinding Background}"/>
                <Label Content="{TemplateBinding Content}"/>
            </Grid>

            <ControlTemplate.Triggers>
                <!-- ウィンドウのサイズが最大の状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Maximized">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </ControlTemplate.Triggers>

        </ControlTemplate>

    </Window.Resources>

ramen-tabero-futsu2-smartphone-size.png
「 👆 バインドしまくって こうかな」

ramen-tabero-futsu2-smartphone-size.png
「 Button は BorderThickness 持ってるかと思ったんだが インテリセンスに出てこなかった。さっぱり分かんね」

Step 20. DataTrigger外に出す

kifuwarabe-futsu-smartphone-size.png
「 ここは むずかしいので、 読み飛ばしてもいいぜ」

kifuwarabe-futsu-smartphone-size.png
「 あれっ、お父ん」

kifuwarabe-futsu-smartphone-size.png
「 [元のサイズに戻す] ボタンと、 [最大化] ボタンの違いって、何だぜ?」

20210925wpf497a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [元のサイズに戻す] ボタンは ウィンドウサイズが normal のときは 場所から消えていて、
[最大化] ボタンは ウィンドウサイズが maximized のときに 場所から消えてることだぜ」

kifuwarabe-futsu-smartphone-size.png
「 そうか、違いがあるのかだぜ」

📖 Wpf button data trigger

ramen-tabero-futsu2-smartphone-size.png
「 👆 しかし 違うところが 少しだけだったら そこだけ外にだしたいよな。
<Button.Style><Style><Style.Triggers> の合わせ技で 外に出せるようだぜ」

kifuwarabe-futsu-smartphone-size.png
「 なんか めんどくさいことに 足を踏み込んでしまったかだぜ」

                <!-- ウィンドウを [元のサイズに戻す]ボタン -->
                <Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click" Template="{StaticResource normalButton}">
                    <Button.Style>
                        <Style TargetType="Button">
                            <Style.Triggers>

                                <!-- ここに DataTrigger が書けます -->

                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                </Button>

                <!-- ウィンドウの [最大化]ボタン -->
                <Button Width="40" Height="30" Content="最大" Click="MaximizedButton_Click" Template="{StaticResource maximizedButton}">
                    <Button.Style>
                        <Style TargetType="Button">
                            <Style.Triggers>

                                <!-- ここに DataTrigger が書けます -->

                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                </Button>

ramen-tabero-futsu2-smartphone-size.png
「 👆 Button 要素に Button.Style 要素をぶら下げられるので」

                                <!-- ウィンドウのサイズがニュートラルな状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Normal">
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                </DataTrigger>
                                <!-- ウィンドウのサイズが最大の状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Maximized">
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                </DataTrigger>

ramen-tabero-futsu2-smartphone-size.png
「 👆 DataTrigger を [Ctrl] + [X] キーで切り取って……」

20210925wpf498a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 貼り付ければ……」

20210925wpf499a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 キー名だけが違う 同じものなんで……」

20210925wpf500a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 normalButton だけ残して maximizedButton の方をバッサリ消して……」

20210925wpf501a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Buttonタグの方の maximizedButton と書いているところを normalButton に書き直せば OK だぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 なんか XAML の グリッド レイアウトを書くところが ぐちゃっと しちゃったわねぇ」

Step 21. 折りたたみボタン

kifuwarabe-futsu-smartphone-size.png
「 その ぐちゃっと している <Style> タグを、 <Window.Resources> タグの中へ 持っていけないのかだぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 やってみるか……。 WPF、 なんか こういうところ ベスト プラクティスは どうすればいいんだろうな」

ramen-tabero-futsu2-smartphone-size.png
「 その前に」

20210925wpf502a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 コードの 左横にある マイナス印のボタン、 折りたたみボタン って言うんだが 使うぜ」

20210925wpf503a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 折りたためるな」

Step 22. Styleをリソースへ

20210925wpf504a1.png

        <!-- [元のサイズに戻す]ボタンのスタイル -->
        <Style x:Key="normalWindowSizeButton" TargetType="Button">
            <Style.Triggers>

                <!-- ウィンドウのサイズがニュートラルな状態のとき、[元のサイズに戻す]ボタンの場所を無くします -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Normal">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>

            </Style.Triggers>
        </Style>

        <!-- [最大化]ボタンのスタイル -->
        <Style x:Key="maximizedButton" TargetType="Button">
            <Style.Triggers>

                <!-- ウィンドウのサイズが最大の状態のとき、[最大化]ボタンの場所を無くします -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"
                                             Value="Maximized">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>

            </Style.Triggers>
        </Style>

ramen-tabero-futsu2-smartphone-size.png
「 👆 <Button> タグから <Style> タグを切り取ったものを [Ctrl] + [V] で貼り付けて、
[元のサイズに戻す] ボタンのスタイルの方には キー名 x:Key="normalWindowSizeButton" を付けて、
[最大化] ボタンのスタイルの方には キー名 x:Key="maximizedButton" を付けるぜ」

20210925wpf505a1.png

                <!-- ウィンドウを [元のサイズに戻す]ボタン -->
                <Button Width="80" Height="30"
                        Content="元サイズ戻す" Click="NormalButton_Click"
                        Template="{StaticResource normalButton}"
                        Style="{StaticResource normalWindowSizeButton}"/>

                <!-- ウィンドウの [最大化]ボタン -->
                <Button Width="40" Height="30"
                        Content="最大" Click="MaximizedButton_Click"
                        Template="{StaticResource normalButton}"
                        Style="{StaticResource maximizedButton}"/>

ramen-tabero-futsu2-smartphone-size.png
「 👆 <Button> から <Style> タグを切り取って 持っていっちゃったんで、
代わりに Style="" というアトリビュートを使って キー名 を指定しておけだぜ」

kifuwarabe-futsu-smartphone-size.png
「 WPFは、こんな めんどくさい 切った貼った をしなくちゃならないのかだぜ?」

ohkina-hiyoko-futsu2-smartphone-size.png
「 自分がやらなくても、他人はやってるから、こういうコードも 読めなくちゃいけないのよ」

ramen-tabero-futsu2-smartphone-size.png
「 そうだぜ」

Step 23. マウス オーバー

20210925wpf480.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ボタンに マウスカーソルが重なっても ボタンに色がついたり、何か見た目に変化が無いの、
押せるのかどうか 分かりづらいぜ」

ramen-tabero-futsu2-smartphone-size.png
「 👆 ControlTemplate を使ったから、もともと ボタンに付いていた機能が消えたんだな。
自力実装する必要があるぜ。説明しよう」

20210925wpf481a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [元のサイズに戻す] ボタンのルックスを作っている Rectangle (四角形)に Name="normalButtonRect" とでも 名前 を付けろだぜ。
同様に [最大化] ボタンの Rectangle にも Name="maximizedButtonRect" とでも名前を付けろだぜ」

                <!--
                    "normalButtonRect" という名前の矩形を、この行より以前に作っておいてください。
                    マウスが重なった時に枠線を青くします
                -->
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter TargetName="normalButtonRect" Property="Stroke" Value="Blue"/>
                    <Setter TargetName="normalButtonRect" Property="Fill" Value="LightBlue"/>
                </Trigger>
                <!--
                    "maximizedButtonRect" という名前の矩形を、この行より以前に作っておいてください。
                    マウスが重なった時に枠線を青くします
                -->
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter TargetName="maximizedButtonRect" Property="Stroke" Value="Blue"/>
                    <Setter TargetName="maximizedButtonRect" Property="Fill" Value="LightBlue"/>
                </Trigger>

ramen-tabero-futsu2-smartphone-size.png
「 👆 Setter タグは、名前の付いているエレメントのプロパティを変えれるんで、それを使うぜ。
<Trigger Property="IsMouseOver" Value="True"> は、 もしも マウスが重なっていたら、ぐらいの意味だぜ」

20210925wpf482a1.png

20210925wpf483a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 マウスカーソルが重なると ボタンに色が付く仕掛けを 自作 したわけだぜ」

参考記事:📖 [WPF] Templateで見た目を変えつつStyleとTriggerでMouseOver等のときの色を変える

Step 24. トリガーを探せ

kifuwarabe-futsu-smartphone-size.png
「 IsMouseOver 以外には、どんなトリガーがあるんだぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 それを調べる方法が 分からないんだぜ。自分流のやり方はあるけど カンペキな答えになってない。説明しよう」

20210925wpf484a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Rectangle というタグの名前のところを右クリックして、 [定義へ移動(G)] をクリックしろだぜ」

20210925wpf485a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Rectangle のソースの 概要だけ見えるんだが、さらに Sharp を右クリックしろだぜ」

20210925wpf486a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 また [定義へ移動(G)] をクリックしろだぜ」

20210925wpf487a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Sharp のソースの 概要だけ見えるんだが、さらに FrameworkElement を右クリックして [定義へ移動(G)] をクリックしろだぜ」

20210925wpf488a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 FrameworkElement のソースの 概要だけ見えるんだが、さらに IInputElement を右クリックして [定義へ移動(G)] をクリックしろだぜ」

20210925wpf489a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 IInputElement のソースの 概要だけ見えるんだが、ここに IsMouseOver の名前が見えるな」

kifuwarabe-futsu-smartphone-size.png
「 あるけど、これが トリガーと紐づく とは思えないぜ」

ramen-tabero-futsu2-smartphone-size.png
「 多分、WPF では DependencyProperty という仕組みが裏で働いていて、これが働いているから、 Property="名前" の形に書けると思うんだぜ。
そこから わたしは慣習に従って IsMouseOverProperty といった名前のプロパティを探すぜ」

20210925wpf490a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 こんどは FrameworkElementUIElement を右クリックして [定義へ移動(G)] をクリックしろだぜ」

20210925wpf492a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 UIElement のソースの 概要だけ見えるんだが……」

20210925wpf493.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 有ったな」

kifuwarabe-futsu-smartphone-size.png
「 ドキュメントの形にしてほしいぜ」

📖 UIElement Class

ohkina-hiyoko-futsu2-smartphone-size.png
「 👆 ドキュメントはあるんだけど、欲しいのと違うのよねえ」

Step 25. マウス プレス

kifuwarabe-futsu-smartphone-size.png
「 ボタンを押したときは、ボタンが押したような見た目になってほしいよな」

ohkina-hiyoko-futsu2-smartphone-size.png
「 マウスボタンが重なったときみたいに、 Rectangleタグに名前を付けて、 マウスボタンを押したというトリガーの中に
Setterタグを置いて Strokeプロパティや、Fillプロパティの色を塗ったらいいんじゃないの?」

kifuwarabe-futsu-smartphone-size.png
「 その、 マウスのボタンを押したトリガー の名前が分からん。 [Ctrl] + [Space] を打鍵しても インテリセンスが出てきてくれないぜ? 」

ramen-tabero-futsu2-smartphone-size.png
「 Style のトリガーに マウスのボタンを押した とか無いのかも知らん。」

📖 WPF: Change background color of border on left mouse button down

ramen-tabero-futsu2-smartphone-size.png
「 👆 Button には IsPressed があるらしいんだが、 Rectangle には無いんだぜ」

kifuwarabe-futsu-smartphone-size.png
「 じゃあ Button の IsPressed を使えばいいのでは?」

20210925wpf506a1.png

20210925wpf494a1.png

                <!--
                    マウス ボタンを押下したときに、背景色を暗くします
                -->
                <Trigger Property="IsPressed" Value="True">
                    <Setter TargetName="normalButtonRect" Property="Stroke" Value="White"/>
                    <Setter TargetName="normalButtonRect" Property="Fill" Value="DarkGray"/>
                </Trigger>

ramen-tabero-futsu2-smartphone-size.png
「 👆 こう書けば いけたぜ」

20210925wpf495a1.png

20210925wpf496a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 マウス ボタンを押下すると 四角形の背景色が 灰色になることで、 ボタンを押したという感じを 視覚的に表現だぜ」

Step 26. 他のボタン スタイル揃え

ohkina-hiyoko-futsu2-smartphone-size.png
「 [最小化] ボタンと、 [閉じる] ボタンは 押下すると 水色っぽい色になるのに、
[元のサイズに戻す] ボタンと、 [最大化] ボタンが ボタンを押下すると 灰色になってて イケてないわよ?」

ramen-tabero-futsu2-smartphone-size.png
「 1か所自作すると 他の自作していないところ 全部気になるしな」

20210925wpf507a1.png

                <!-- ウィンドウの [最小化]ボタン -->
                <Button Width="40" Height="30" Content="最小"
                        Click="MinimizedButton_Click"
                        Template="{StaticResource normalButton}"/>

                <!-- ウィンドウを [元のサイズに戻す]ボタン -->
                <Button Width="80" Height="30" Content="元サイズ戻す"
                        Click="NormalButton_Click"
                        Template="{StaticResource normalButton}" Style="{StaticResource normalWindowSizeButton}"/>

                <!-- ウィンドウの [最大化]ボタン -->
                <Button Width="40" Height="30" Content="最大"
                        Click="MaximizedButton_Click"
                        Template="{StaticResource normalButton}" Style="{StaticResource maximizedButton}"/>

                <!-- ウィンドウを [閉じる]ボタン -->
                <Button Width="40" Height="30" Content="閉じ"
                        Click="CloseButton_Click"
                        Template="{StaticResource normalButton}"/>

ramen-tabero-futsu2-smartphone-size.png
「 👆 4つのボタンそれぞれに 同じテンプレートを付けようぜ?」

ohkina-hiyoko-futsu2-smartphone-size.png
「 この グリッド レイアウト の XAML が 見やすくなるように 脳をフル回転 させてんのね」

kifuwarabe-futsu-smartphone-size.png
「 他人が書いた Template とか Style とか、結局
コード書いて 実行してみるまで何が起こるか分からないから、
再利用するために必要な勘が無くて、一から書き直す ことになるよな」

ramen-tabero-futsu2-smartphone-size.png
「 圧倒的に 自由自在に WPF を使いこなす底力を上げるしかないぜ。
前担当者のスキルレベルを計れる程度に自分が詳しくなければ、自分に把握できないコードが出てくるぜ

Step 27. ウィンドウをつかめ

kifuwarabe-futsu-smartphone-size.png
「 お父ん、タイトルバー無くなったんで マウスでつかむところ無いぜ。
どうやって デスクトップ上で ウィンドウを移動させるんだぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 まず、 アプリケーションに マウスが当たってるかどうか の判定をしたいよな」

20210921wpf260a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 デザインで ちり紙 を選んで 雷マークを選んで MouseDown の右横のテキストボックスを ダブルクリックしてくれだぜ」

20210921wpf261a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 コードが出てきて、 Rectangle_MouseDown というスケルトンができてるな」

20210921wpf262.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 メソッド名を選択して 右クリックから 名前の変更 で、 DustPaper_MouseDown という名前に変えてみようぜ?
雰囲気出るな」

20210921wpf263.png

        private void DustPaper_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Trace.WriteLine($"マウスボタンを押下しました。 sender.GetType()=[{sender.GetType()}]");
        }

ramen-tabero-futsu2-smartphone-size.png
「 👆 上記のように1行書き込んでほしいんだが、赤い波線と 豆電球のマークが出ているな。
コンパイル時エラーだぜ」

20210921wpf264a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 赤い波線は 直せることが多い。 赤い波線にカーソルを合わせて じっとしろだぜ。
近くに豆電球マークが出てきたらクリック、
修正方法、または 要らんことの いずれかが出てくるから今回は using System.Diagnostics; をクリックしろだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 直し方を知っている人しか 使いこなせないわよね 豆電球」

ramen-tabero-futsu2-smartphone-size.png
「 慣れてくれば ガチャガチャ をやりだすぜ。 つまり 選んで直ればOK、直らなければ アンドゥ を繰り返すんだぜ」

20210921wpf265a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 足りてなかった必要な行を 足してくれたんだぜ」

20210921wpf266.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 エラーが取れたら……」

20210921wpf267a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 右クリックから デザイナーの表示 で デザイナーへ戻って」

20210921wpf268a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 MouseDown="DustPaper_MouseDown" のところを [Ctrl] + [C] でコピー」

20210921wpf269a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 他のちり紙にも [Ctrl] + [V] で貼り付けろだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 実行して これで ちり紙の上で マウスクリックすれば 反応があるかというと……」

20210919wpf136a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 なんか上に文字が乗っていてな。失敗する。思ってるようには反応しないぜ」

kifuwarabe-futsu-smartphone-size.png
「 文字をクリックしたかったのか、紙をクリックしたかったのか 分からんからなあ。
だから Windows のルックスには タイトルバーがあったんだぜ」

📖 WPF マウスクリックイベントを透過WPF マウスクリックイベントを透過

ohkina-hiyoko-futsu2-smartphone-size.png
「 👆 文字は 受け取ったマウスダウン イベントを 後景のちり紙に 投げ下げる仕組みが なんかあるみたいよ?」

20210921wpf270a1.png

IsHitTestVisible="False"

ramen-tabero-futsu2-smartphone-size.png
「 👆 これを文字に付けるだけかだぜ」

20210921wpf271a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 おお、文字の後ろの四角形に マウスダウンが利いたぜ!」

20210919wpf138a1.png

        /// <summary>
        /// 紙の上でマウスボタンを押下したとき
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var coord = ((Visual)sender).PointToScreen(e.GetPosition((IInputElement)sender));
            Trace.WriteLine($"マウスボタンを押下しました。 sender.GetType()=[{sender.GetType()}] x=[{coord.X}] y=[{coord.Y}]");
        }

📖 WPFでマウス操作の練習をしようぜ(^~^)?

ramen-tabero-futsu2-smartphone-size.png
「 👆 マウスカーソルのスクリーン座標での位置の取得の仕方は、以前に練習して記事にしてあるんで気になったら参照しろだぜ」

Step 28. ウィンドウ外キャプチャ無理

20210920wpf139.png
(👆 ウィンドウ外にマウスカーソルが出ても、マウスの押下状態はキャプチャーされるか?)

ramen-tabero-futsu2-smartphone-size.png
「 👆 押下したマウスボタンを離した瞬間をウィンドウは知らないのに、マウスボタンが離されていることって いっぱいあるだろ」

kifuwarabe-futsu-smartphone-size.png
「 ポップアップが飛び込んでくるような迷惑行為とか、 移動するオブジェクトの方が マウスカーソルの指しているところから出ていったり」

ohkina-hiyoko-futsu2-smartphone-size.png
「 マウスリリースのイベントが ウィンドウ外で起こっても拾うかどうかってことよね。
試してみましょう」

20210921wpf272a1.png

20210921wpf273a1.png

        private void DustPaper_MouseUp(object sender, MouseButtonEventArgs e)
        {
            var coord = ((Visual)sender).PointToScreen(e.GetPosition((IInputElement)sender));
            Trace.WriteLine($"マウスボタンが離されました。 sender.GetType()=[{sender.GetType()}] x=[{coord.X}] y=[{coord.Y}]");
        }

ramen-tabero-futsu2-smartphone-size.png
「 👆 マウスアップを付けてみたぜ」

20210920wpf142a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ダメだったぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 マウスカーソルがウィンドウの範囲外に行ってしまったときのマウスボタンの状態変化は キャプチャーしてくれないのね」

ramen-tabero-futsu2-smartphone-size.png
「 👆 マウスカーソルが ウィンドウから出たり 入ったりするとき MouseLeaveMouseEnter イベントの通知を
受け取ることができるはずだから、そこで マウスボタンが押されているか 離されているか 調べることにしようぜ?」

Step 29. マウス押下座標、記憶

ramen-tabero-futsu2-smartphone-size.png
「 👆 ViewModels フォルダーを前に作ってあると思うが……」

20210920wpf143a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ViewModels フォルダーの下に クラスを作ろうぜ?
[ViewModels]フォルダー - [追加] - [クラス]

20210920wpf145a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ファイル名は MainWindowViewModel で」

20210920wpf146a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 作った MainWindowViewModel.cs ファイルのコード画面で 右クリック、 Using の削除と並び替え を選ぶと」

20210920wpf147a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 使ってない using 文を消してくれるぜ。すっきりしたな」

ohkina-hiyoko-futsu2-smartphone-size.png
「 Go言語と Visual Studio Code の組み合わせなら オートでやってくれるのに」

20210920wpf148a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 次に手動で namespace に .ViewModels と打鍵してくれだぜ。
そして class の左側に public と打鍵してくれだぜ」

20210921wpf274a1.png

Window タグに:

        xmlns:viewModels="clr-namespace:WpfExerciseDustPaperOnDesktop.ViewModels"

Window タグの子要素として:

    <!-- このウィンドウに紐づくViewModelです -->
    <Window.DataContext>
        <viewModels:MainWindowViewModel/>
    </Window.DataContext>

ramen-tabero-futsu2-smartphone-size.png
「 👆 そのあと 上記のように 2か所追加してくれだぜ。
これで MainWindow.xaml ファイルと MainWindowViewModel.cs ファイルは なんか関係あるんだな、
ということが Visual Studio に伝わるんで 便利になるぜ」

20210921wpf275a1.png

namespace WpfExerciseDustPaperOnDesktop.ViewModels
{
    using System.Windows;

    public class MainWindowViewModel
    {
        /// <summary>
        /// マウスボタンを押下した地点です。スクリーン座標です
        /// </summary>
        public Point StartPoint { get; set; }
    }
}

ramen-tabero-futsu2-smartphone-size.png
「 👆 最初に書くコードは これぐらいかな」

20210921wpf276a1.png

            var viewModel = this.DataContext as MainWindowViewModel;
            viewModel.StartPoint = coord;

ramen-tabero-futsu2-smartphone-size.png
「 👆 2行書き足してくれだぜ。 赤い波線のとこ エラーなんだが」

20210921wpf277a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 豆電球をクリックして
using WpfExerciseDustPaperOnDesktop.ViewModels; を選んで 修正してくれだぜ」

Step 30. 実行中の変数、中身確認

ramen-tabero-futsu2-smartphone-size.png
「 コーディングして疲れただろ、動かして 書いたコードが何してるか 見てみようぜ?」

20210921wpf278a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 viewModel.StartPoint = coord; と書いた行の テキストエディターの左側の端っこの 灰色のところをクリックしてくれだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 何もないとこ クリックすんの?」

ramen-tabero-futsu2-smartphone-size.png
「 そうだぜ」

20210921wpf279a1.png

ohkina-hiyoko-futsu2-smartphone-size.png
「 何か 赤い丸が付いたわよ?」

ramen-tabero-futsu2-smartphone-size.png
「 それが ブレークポイント だぜ」

20210921wpf280a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 じゃ、 画面上の方の 緑色の右向きの三角形のあたりをクリックして デバッグ実行してみようぜ?」

20210921wpf281.png

kifuwarabe-futsu-smartphone-size.png
「 👆 べつに何も変わらんが」

ramen-tabero-futsu2-smartphone-size.png
「 ちり紙を クリックしろだぜ」

20210921wpf282a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 なんか黄色くなったぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 制御(せいぎょ) が ブレークポイントで止まったんだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 止まってどうすんの?」

20210921wpf283a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 StartPoint にカーソルを合わせろだぜ。 0, 0 っていう数が 出てくるぜ」

20210921wpf285a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 左側の三角形をクリックすれば、これが x 座標、 y 座標 ってことが分かるな。まだ 0 が入ってるぜ」

20210921wpf284a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ピン マークをクリックしてみろだぜ」

20210921wpf286a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ポップアップが出てきて、表示を出しておけるぜ」

20210921wpf287.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 coord も同様だぜ。 出てくるボタン押しまくって自習しろだぜ」

20210921wpf289a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 デバッグ ツール バーの [ステップ オーバー] をクリックしろだぜ。 F10 キーを打鍵しても同じ」

20210921wpf290a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 StartPoint の中身が変わったな。1行実行されたんだぜ」

kifuwarabe-futsu-smartphone-size.png
「 代入だしな」

20210921wpf291a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 気が済んだら 続行ボタンをクリックしろだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 こういう 数が格納されてるやつ 変数(へんすう) というが、変数の中身は確認できることは分かったな。
いったん ちり紙を閉じろだぜ」

Step 31. MouseMove 忘れてた

20210921wpf292a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 MouseMove イベントの ハンドラ も付けといてくれだぜ」

20210921wpf293a1.png

        private void DustPaper_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            var coord = ((Visual)sender).PointToScreen(e.GetPosition((IInputElement)sender));
            Trace.WriteLine($"マウスを動かしました。 sender.GetType()=[{sender.GetType()}] x=[{coord.X}] y=[{coord.Y}]");

            if (e.LeftButton==MouseButtonState.Pressed)
            {
                // マウスの左ボタンが押下されているとき
                var viewModel = this.DataContext as MainWindowViewModel;

                // メイン ディスプレイの表示の拡大率を取得します
                Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
                var widthRate = m.M11;
                var heightRate = m.M22;

                // 拡大されたサイズで計算したあと、拡大率を 100% に戻してセットします
                this.Left += (coord.X - viewModel.StartPoint.X) / widthRate;
                this.Top += (coord.Y - viewModel.StartPoint.Y) / heightRate;

                viewModel.StartPoint = coord;
            }
        }

ramen-tabero-futsu2-smartphone-size.png
「 👆 コードは これを貼り付けてくれだぜ」

Step 32. ちり紙を動かせ

20210922gif5.gif

kifuwarabe-futsu-smartphone-size.png
「 👆 やったぜ! デスクトップ上で ちり紙を ドラッグ&ドロップすることが できるようになったぜ!」

ohkina-hiyoko-futsu2-smartphone-size.png
「 やったわね!」

ramen-tabero-futsu2-smartphone-size.png
「 やったぜ!」

Step 33. アイコン

20210922wpf294a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 この かっこわるいアイコンは なんとかならんのかだぜ?」

20210922wpf295a1.png

📖 方法: アプリケーション アイコンを指定する (Visual Basic、C#)

ramen-tabero-futsu2-smartphone-size.png
「 👆 ソリューション エクスプローラー から プロジェクトを右クリックして、プロパティ をクリック」

20210922wpf296a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [アプリケーション] - [リソース] - [参照...] をクリックして アイコン ファイルを選べば OK だぜ。
ただ、どうやって アイコン(.ico)ファイルを作るんだ、という話しはある」

ohkina-hiyoko-futsu2-smartphone-size.png
「 1つの .ico ファイルに 小さなアイコン、大きなアイコン と複数 入ってるから、ただの画像じゃないのよ」

📖 Greenfish Icon Editor Pro

ohkina-hiyoko-futsu2-smartphone-size.png
「 👆 まどのもり に アイコンを作る無料のエディターとか あるけど、海外製で とっつきにくいのよね」

20210922wpf297.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 あれっ インターフェースが とっつきやすくなってる!」

20210922wpf298a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 32 x 32 サイズで 作って ファイル選択」

20210922wpf299a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 他のアイコンと同じように 並んだぜ」

Step 34. リリース ビルド

20210923wpf300a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 今まで ずっと [ソリューション構成] ドロップダウンリストが Debug のまま 実行してたと思う」

20210923wpf301a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ここから Release (リリース)に切り替えることができるぜ。
初めて アプリケーションを作ったばかりで 使い込んでいない今の段階では なんか Release モードにしたからといって 嬉しいことは無いと思うぜ」

ramen-tabero-futsu2-smartphone-size.png
「 企業になると 〇〇社様向けリリース とか納品先によって 成果物を分けたり、
〇〇製品(2019年春)〇〇製品(2021年夏) といった感じで 製品を分けたり、
〇〇社様向け_〇〇製品(2021年夏)_Debug とか合体して 枝分かれが爆発して 大変な行数になる」

ramen-tabero-futsu2-smartphone-size.png
「 コンピューター将棋だと Learning モードとか あったかな」

kifuwarabe-futsu-smartphone-size.png
「 👆 じゃあ Debug とか Release とかは 初期設定で2個用意されてるだけで 違いはないのか?」

ramen-tabero-futsu2-smartphone-size.png
「 違いはある。 むしろ Release モードのこと よく分かってなければ Debug モードのまま配布した方が
開発中のコードと同じ動きをするぜ。
限界の環境の中では、誰もメンテナンスしていない リリースモード を選ぶよりは、達人は Debug モードのまま リリースする」

ohkina-hiyoko-futsu2-smartphone-size.png
「 わらう」

20210923wpf302a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 リリース モードで実行すると」

20210923wpf303a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ブレークポイント を無効にして 実行するなら [デバッグの続行] 、
Release モードだけど やっぱ ブレークポイント 使いたい、デバッグしたい というときは [マイ コードのみ]を無効にして続行 を選べだぜ」

kifuwarabe-futsu-smartphone-size.png
「 何なんだぜ それ!」

ohkina-hiyoko-futsu2-smartphone-size.png
「 Release モードを デバッグしたいときって もちろん あるのよ」

20210923wpf304a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 おっ ブレークポイント が無視されてるぜ。 重要な機能なんじゃないのか これ?」

ramen-tabero-futsu2-smartphone-size.png
「 デバッグモードで配布して ブレークポイントで止まってたら いやだしな」

ramen-tabero-futsu2-smartphone-size.png
「 ちり紙は閉じてくれだぜ」

20210923wpf310a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ソリューション エクスプローラー から プロジェクト名を右クリックして
プロパティ をクリックしてくれだぜ」

20210923wpf311a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [ビルド] - [出力] とクリックしてくれだぜ。 なんか bin\ と書いているのが分かれば OK だぜ。
[×] 印をクリックして プロパティは閉じてくれだぜ」

20210923wpf305a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 続いて ソリューション エクスプローラー から プロジェクト名を右クリックして
エクスプローラーでフォルダーを開く をクリックしてくれだぜ」

20210923wpf306a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 bin フォルダーを開けていってくれだぜ」

20210923wpf307a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 .exe ファイルができてるから、ダブルクリックしてくれだぜ」

20210923wpf308.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ちり紙 がでてきたぜ」

20210923wpf309a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 作った WPF アプリケーションを配布するときは、このフォルダーの中身を全部 渡せだぜ。
もっと 大がかりなアプリケーションになると、 別のフォルダーと連携したりするんで、大変だが、
この演習課題ぐらいの規模なら フォルダー1つだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 Rust言語なら .exe ファイル1つに全部かためてくれるのに、 WPFは もっさりしてるわねぇ」

Step 35. ソリューション プラットフォーム

20210924wpf448a1.png

ramen-tabero-futsu2-smartphone-size.png
「 標準ツールバー で、 ソリューション プラットフォーム というのを 選べるんだが、
Any CPU にしとけば 32bit CPU でも 64bit CPU でも どちらでも動くから、 PC(パソコン) では ふつうの選択肢だぜ」

ramen-tabero-futsu2-smartphone-size.png
「 また、 32bit CPU のことを x86 と よく呼ぶぜ。 Any CPU にしておくと x86 のプログラムとしてインストールされるぜ」

ramen-tabero-futsu2-smartphone-size.png
「 これを 64bit CPU でしか動けなくする のが、 x64 という設定だぜ。
なんで そんな不便なことをするのかというと、ゲーム機とか 32bit に対応する用意がないマシンで動かすときのためだな」

20210924wpf450a1.png

ramen-tabero-futsu2-smartphone-size.png
「 Cドライブの下の Program Files フォルダーも、 64bit CPU か、 32bit CPU かで分かれているな。
x86 と書いてあるのは 今では 32bit CPU でしか動かないのではなく、 32bit CPU でも動く 64bit CPU のアプリ ぐらいに思っておけだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 じゃあ Any CPU のままでいい気がするなあ」

kifuwarabe-futsu-smartphone-size.png
「 どうやって x64 の設定にするんだぜ?」

20210924wpf449a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 構成マネージャー... をクリックしろだぜ」

20210924wpf451a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 DebugAny CPU にして、 Releasex64 にするとか、分けることもできるぜ。
というか、分かれているんだぜ。 だから Debug の分と Release の分、両方 設定しないといけないぜ」

20210924wpf452a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [アクティブ ソリューション プラットフォーム]ドロップダウンリスト から <新規作成...> を選べだぜ」

20210924wpf453.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 で、今までに Any CPU にいろんな設定をしてあるだろうから、それを引き継いで 新しく作ろうぜ、という画面だぜ。
ここで」

20210924wpf454a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 x64 を選んで [OK] をクリックしろだぜ」

20210924wpf455a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 分かりにくいんだが、親子関係になっていて、 Debugx64 は こんなテーブルですよ、という表示になっているぜ。
WpfExerciseDustPaperOnDesktop プロジェクトの Debug 構成では プラットフォームは x64 ですよ、と書いてあるんだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 [閉じる] をクリックしろだぜ」

20210924wpf456a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 これで Debug モードでは、 x64 専用の実行ファイルが作られるぜ。
今どき 32bit CPU で動くことまで考えておかなければいけないケースは、ふつうは、無いから x64 専用でいいだろ」

Step 36. デプロイ

20210923wpf312a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ちり紙 を すべてのアプリの一覧に並べるには どうやったらいいんだぜ?」

ramen-tabero-futsu2-smartphone-size.png
「 それ ショートカット置いてるだけ なんだけどな」

20210923wpf313a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Cドライブの下の Program Files を開けてくれだぜ」

20210923wpf314a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 まあ すでに色々 入ってると思うが……」

20210923wpf315a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [ホーム] - [新しいフォルダー] をクリックしてくれだぜ」

20210923wpf316.png

kifuwarabe-futsu-smartphone-size.png
「 👆 わらう」

ramen-tabero-futsu2-smartphone-size.png
「 構わず [続行] で」

20210923wpf317a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 なんか フォルダー名に 半角スペース含めるの 違和感あるんだが、周りに雰囲気を揃えた感じの 被らなさそうな名前を付けてくれだぜ」

20210923wpf318a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 .exe が入っているフォルダーを 左に、
Program Files の下に作ったフォルダーを開けて 右に 見えるよう ファイル エクスプローラー を並べたあと、
コピーしたいフォルダーを マウスの右ボタンでクリックして、 マウスカーソルを 右側の ファイル エクスプローラーに移動しろだぜ」

20210923wpf319a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 コンテキスト メニューが出てくるんで、 [ここにコピー] をクリック」

20210923wpf320a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 アクセスが拒否されるが、構わず [続行] をクリック」

20210923wpf321a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 フォルダー名を ちょんとクリックして 名前を変えようぜ? dust-paper-on-desktop とかでどうだぜ?」

20210923wpf322a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 構わず 続行 をクリック」

20210923wpf323a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 dust-paper-on-desktop フォルダーを開いて .exe ファイルを右クリック、 [ショートカットの作成] をクリック」

20210923wpf324a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 こんなとこにショートカットは作れないが デスクトップに作るのなら大目に見てやろうと コンピューター様が おっしゃっているんで
はい をクリック」

20210923wpf325a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 デスクトップに ショートカットができているな?」

20210923wpf326a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ファイル エクスプローラーから C:\ProgramData\Microsoft\Windows\Start Menu\Programs へアクセスしろだぜ」

20210923wpf327a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ちり紙へのショートカットを右クリック、 ファイル エクスプローラーの タイトルバーの辺りでマウスボタンを離せだぜ」

20210923wpf328a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ここにコピー をクリック」

20210923wpf329a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 続行 をクリック」

20210923wpf330a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ショートカット を作れたな」

20210923wpf331a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 でけたぜ」

kifuwarabe-futsu-smartphone-size.png
「 めんどくさ!

Step 37. インストーラー作成

📖 Deploy a WPF Application

ohkina-hiyoko-futsu2-smartphone-size.png
「 👆 デプロイ(Deploy;ファイルなどの配置、それに関する設定)めんどくさいから インストーラーを作りましょう」

ramen-tabero-futsu2-smartphone-size.png
「 Microsoft のドキュメントが推奨する製品 使い方 わけ分からんので 他のを当たろうぜ」

📖 なつかしの Visual Studio Installer(の後継)を現役のVisual Studioで使用する

ramen-tabero-futsu2-smartphone-size.png
「 👆 2000年の '00年代は ワケ分からんかったが、 2020年にもなれば 幾分 マシになってるだろうか」

20210923wpf335.png

📖 Microsoft Visual Studio Installer Projects 2022

ramen-tabero-futsu2-smartphone-size.png
「 👆 ブログ記事読んでたら 2019 用だったんで、探したら 2022 Preview 用のがあったぜ」

20210923wpf336a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 インストールし直しで」

ramen-tabero-futsu2-smartphone-size.png
「 Visual Studio を使っていると インストール進まないみたいなんで、 Visual Studio は閉じておけだぜ」

20210923wpf337.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 インストールできたようだな。使ってみるか……。
VSIX ってのは Visual Studio に機能が付くんだぜ」

20210923wpf338a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 2行目の プロジェクトではなく、 1行目の ソリューション を右クリック、
[追加] - [新しいプロジェクト] をクリック」

20210923wpf339a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Setup Project をクリックして [次へ]

20210923wpf377a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 プロジェクト名には 何をインストールするのか分かるような名前を付けろだぜ。
例えば Setup1 を SetupWpfExerciseDustPaperOnDesktop に変えて [作成] をクリック」

20210923wpf378a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 SetupWpfExerciseDustPaperOnDesktop プロジェクトが増えてんな」

20210923wpf388a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 この最初の画面は [SetupWpfExerciseDustPaperOnDesktop]プロジェクト を右クリックして
[View] - [ファイル システム] をクリックすれば出てくるんで、閉じてしまったときに また出すために 覚えておけだぜ」

20210923wpf379a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ソリューション エクスプローラーから [SetupWpfExerciseDustPaperOnDesktop]プロジェクト を ちょんとクリックすると
プロパティ が表示されるぜ」

20210923wpf371a2.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Author には作者名を入れろだぜ。ファイルを右クリックしたときのプロパティに出てくる。
Manufacturer は 製造した団体名でも入れろだぜ。インストール先のディレクトリー名になる。
ProductName は (インストーラーではなく)インストールしたいアプリの名前を入れろだぜ。
Title は、どこで使われるんだろうなあ」

ramen-tabero-futsu2-smartphone-size.png
「 RemovePreviousVersions を True にしておくと、古いバージョンがインストールされていれば消してくれるぜ」

20210923wpf369.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 例えば 古いバージョンがすでにインストールされていて、 RemovePreviousVersions を True に設定してないと 上書きインストールできないぜ。
Version 番号をこまめに設定してないと意味ない」

Step 38. プラットフォーム選べ

20210924wpf457a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 配布するものは Release ビルドを使うのが ふつう だぜ。
とはいえ、世の中 ふつうではないとき だってあるので ふつうではないときDebug でビルドして配布することもあるだろう」

ohkina-hiyoko-futsu2-smartphone-size.png
「 ふつうでありたいものね」

ramen-tabero-futsu2-smartphone-size.png
「 このあと、うまくいかないこともあるだろうから、そのときは Any CPU を選んで やり直してくれだぜ」

20210923wpf381a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Application Folder] - [Add] - [プロジェクトの出力] をクリック」

20210924wpf460a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ここで 気にしたいのは 構成 なんだが、何それ? と言うと……」

20210924wpf461a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 画面 上の方の 標準ツール バーで選ばれているのを (アクティブ) と呼んでいて、
ここでは 間違えのないように Release x64 を明示的に選ぶかだぜ」

ohkina-hiyoko-futsu2-smartphone-size.png
「 上のでっかい Release とか x64 は これからのインストールで 関係なくて、ここで選んだやつが関係あるのね」

20210924wpf462a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [OK] をクリック」

20210924wpf463a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 これが ユーザーのみなさんの、アプリケーションを入れておくためのフォルダーに デプロイ(配備)したいもの に相当するぜ。
.exe ファイルとか入ってるフォルダーとかのことだな」

20210924wpf466a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 そして セットアップのプロジェクトのプロパティで TargetPlatformx86 になってるかもしれないから……」

20210924wpf467a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 忘れずに x64 に変えておいてくれだぜ」

Step 39. ライセンス条項、用意

ramen-tabero-futsu2-smartphone-size.png
「 ライセンス条項 は、 むずかしいから、 分からん人は 読み飛ばせだぜ」

📖 ライセンスのファイル名はどうすべきか?

20210923wpf395a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Windows のタスク バーから [スタート]ボタン - [Windows アクセサリ] - [ワードパッド] をクリック」

20210923wpf396.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 無限に長い紙みたいなのが出てくるぜ。 これを用意しつつ……」

ramen-tabero-futsu2-smartphone-size.png
「 わたしは MITライセンス を拾ってくるぜ。 お前がどのライセンスを選ぶかは知らん」

20210923wpf386.png

📖 The MIT License

ramen-tabero-futsu2-smartphone-size.png
「 👆 MITライセンス の原文を ここから 全文選択、コピーし」

20210923wpf397.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 WordPad に貼り付け」

20210923wpf398a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 <YEAR> <COPYRIGHT HOLDER> を今の年と 自分の名前に書きかえるぜ。
オープンソースのコミュニティとかの プログラマーの文化的には ここにはコードの作成に直接関わった人間の名前を つらつら書き、 本名が普通だが、
ここは プログラミングの範疇ではなく 法律の範疇なんで お前のことは わたしは知らんので お前の思うようにやれだぜ」

20210923wpf399a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 保存先は あとで移動させるとして どこでもよくて、
[リッチ テキスト形式 (RTF) (*.rtf)]ファイル を選択、 LICENSE.rtf といった名前を付けて [保存] をクリック」

ramen-tabero-futsu2-smartphone-size.png
「 この .rtf とかいうファイル、 WordPad とかで作れるファイル フォーマットで、 わたしは パーサーを書いたこともあるが 読みにくくて嫌になった。
ぜったい XML ファイルとか HTML/CSS の方が優れていると思うぜ」

20210923wpf389a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ライセンスのファイルを添付するために、 [Application Folder] - [Add] - [ファイル] をクリックしろだぜ」

20210923wpf400a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 さっき作った ライセンスのファイルを開けだぜ」

20210923wpf401a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 頒布したいプロジェクトの方ではなく、インストーラーのプロジェクトの方にコピーするわけだぜ」

20210923wpf392a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 次に [WpfExerciseDustPaperOnDesktop]プロジェクト右クリック - [View] - [ユーザー インターフェース] と進んで」

20210923wpf346a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Install] - [Start] - [ダイアログの追加] と進めだぜ。
これって インストーラーの出てくる画面の順になってそうだよな」

20210923wpf347a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [ライセンス条項] - [OK] と進めだぜ」

kifuwarabe-futsu-smartphone-size.png
「 ぜったい ちり紙に ライセンス条項 要らないと思う」

20210923wpf348a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 右クリックすると 上へ移動 などで順を変えれるそうだぜ」

20210923wpf349a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ライセンス条項 を選んだまま プロパティ ペーンから License File のドロップダウンリストをクリックして
[(Browse...)] を選ぶと インストーラーで添付したファイルを選べるようなんだぜ」

20210923wpf402a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 いろんな種類が選べそうな見た目をしていたが、 テキストファイル(.txt) では ビルド通らなかった。
リッチ テキスト フォーマット(.rtf) にして進めてみるかだぜ」

Step 40. アイコン入れろ

20210924wpf432a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Application Folder を右クリックして [Add] - [ファイル] と進めだぜ」

20210924wpf433a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 まえに アイコン( .icoファイル)作っただろ。 選べだぜ」

20210924wpf434a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 入ったら OK だぜ」

Step 41. ショートカット作成

20210924wpf418a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 どこを右クリックすりゃいいのか よく分かってないが なんか右クリックして 新しいショートカットの作成 をクリックしろだぜ」

20210924wpf419a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Application Folder をダブルクリックしろだぜ」

20210924wpf420a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 項目の公開 from WpfExerciseDustPaperOnDesktop (Active) をクリックして [OK] をクリックしろだぜ」

20210924wpf421a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 増えてるな」

20210924wpf422a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 2つ欲しいんで、同じ操作を もう1階 しろだぜ」

20210924wpf423a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 名前変えたいんで、右クリックして [名前の変更]

20210924wpf424a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 例えば Dust paper on the desktop とかに変えようぜ」

20210924wpf425a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 もう片方も同じ名前にしたいんだが、同じ名前のファイルがあるとできないんで ちり紙 とでもしておくぜ」

Step 42. ショートカット アイコン

20210924wpf435a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Dust paper on the desktop を選んで プロパティ ペーン の [Icon]ドロップダウンリスト から (Browse...) をクリック」

20210924wpf436a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Browse...]ボタン をクリック」

20210924wpf437a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [Application Folder] をダブルクリック」

20210924wpf438a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 アイコン ファイル(.ico) を選んで [OK] をクリック」

20210924wpf439a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 なんだかわかんないんで [OK] をクリック」

20210924wpf440a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 これでショートカットに アイコンが付いているぜ」

20210924wpf441a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ちり紙 ショートカットにも同様に アイコン を付けておいてくれだぜ」

Step 43. ショートカット デプロイ

20210924wpf426a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Dust paper on the desktop をマウスでドラッグして User's Programs Menu フォルダーへマウスでドラッグ&ドロップしろだぜ」

20210924wpf427a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 ちり紙 をマウスでドラッグして User's Desktop フォルダーへマウスでドラッグ&ドロップしろだぜ」

20210924wpf428a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すると User's Desktop フォルダーに ちり紙 が入ってるな」

ohkina-hiyoko-futsu2-smartphone-size.png
「 迷惑よね」

20210924wpf429a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すると User's Programs Menu フォルダーに Dust paper on the desktop が入ってるな」

kifuwarabe-futsu-smartphone-size.png
「 むしゃくしゃした気分のときに このアプリを実行するんだな」

Step 44. インストーラー ビルド

20210924wpf459a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [WpfExerciseDustPaperOnDesktop] プロジェクトを右クリックして [リビルド] をクリックしろだぜ」

20210924wpf468a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 失敗が 0 なら OK」

20210923wpf405a1.png

Step 45. インストーラー 実行

ramen-tabero-futsu2-smartphone-size.png
「 👆 [WpfExerciseDustPaperOnDesktop]プロジェクト を右クリック、 [エクスプローラーでフォルダーを開く] をクリック」

20210923wpf406a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 Release フォルダーを開いていけだぜ」

20210923wpf407a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 SetupWpfExerciseDustPaperOnDesktop.msi ファイルができてるな。ダブルクリックしろだぜ」

20210923wpf411a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 プロジェクト名ではなく、もっと かっこいい製品名にしなかったのかだぜ」

ramen-tabero-futsu2-smartphone-size.png
「 あれま」

20210923wpf409.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ライセンス条項、さっき作ったファイル でてきたな」

ramen-tabero-futsu2-smartphone-size.png
「 [同意する] を選んで 次へ」

20210924wpf469a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 Program Files (x86) の方ではないことを確認」

ramen-tabero-futsu2-smartphone-size.png
「 次へ」

20210923wpf413.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 次へ」

20210923wpf414.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ほんとにインストールは完了したのかなあ? [閉じる] ぜ」

20210924wpf470a1.png

ohkina-hiyoko-futsu2-smartphone-size.png
「 👆 ほんとに Doujin Soft Circle Grayscale があるわよ」

20210924wpf471a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 中身もちゃんと デプロイされてるようだぜ」

20210924wpf442a1.png

kifuwarabe-futsu-smartphone-size.png
「 👆 ちり紙ができてるぜ」

20210924wpf443a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 すべてのアプリケーション一覧に Dust paper on the desktop ができてるぜ」

📖 Visual Studio 2019でインストーラを作成
📖 Visual Studio 2019でインストーラの作り方
📖 Visual Studio Installer Deployment
📖 How to Create Setup.exe in Visual Studio 2019 using VS Installer Projects

ramen-tabero-futsu2-smartphone-size.png
「 👆 他に分かんないところがあれば、自分で調べてくれだぜ」

Step 46. アンインストール

kifuwarabe-futsu-smartphone-size.png
「 こんなアプリ、消してしまおうぜ!」

20210923wpf372a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 アンインストールするには [Windows スタート]ボタン - [設定] と進み」

20210923wpf373a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 アプリ をクリック」

20210923wpf374a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 消したいアプリをクリック」

20210923wpf375a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 [アンインストール]ボタン が出てくるのでクリック」

20210923wpf376a1.png

ramen-tabero-futsu2-smartphone-size.png
「 👆 なんで2回出てくる! [アンインストール]ボタン をクリック。
すぐには 反映されないが、数秒で 消えるぜ」

この記事に向かってリンクしてる記事

📖 WPFって何だぜ(^~^)?

ツイッターでシェア
みんなに共有、忘れないようにメモ

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント