(👆 2021年の現代で Windows専用の縛りがあって 誰が興味持つのか分からないが……)
📖 wpf-exercise-dust-paper-on-desktop - Git hub に上げたもの
「 Webアプリ15年ぐらい経験あるんで、 WPF? 応用で 簡単 簡単、と思って 面談通って 派遣入場したら WPF 思ってたやつと全然違った」
「 お父んが 持ってないスキルだったもんな、 MVVM。 持ってないスキルで 派遣入場決めたの わらう」
「 座学退屈なんで 手を動かして 作りながら スキルを身に付けれるような 演習問題、わたしが欲しいのに無いんで 自分で作るぜ」
「 1990年代は プログラミング月刊雑誌 いっぱいあったのよ。 12か月購読すれば アプリケーションが1つ作れます、みたいな」
「 👆 Windows のアプリケーションを作るぞ! と思って 最初にやりたくなるのは Windows みたいな ウィンドウを消すことだと思うんだぜ」
「 👆 だから最初の演習問題 『デスクトップ上のちり紙』 では Windows みたいなウィンドウを消すことをやるぜ」
「 この演習問題の所要時間は、 どれぐらい初心者かにもよるが 集中すれば 土曜日1個消し飛ぶ程度で済むぐらいを想定」
「 この記事はどんどん転載したり、生配信したり コピー、加工しまくれだぜ
ただし 何も正しさは保証しないし この記事を元に何かして損害が起こっても責任は取らないぜ」
📖 Visual Studio 2022 Preview をインストールしようぜ(^~^)?
「 おっ、 Visual Studio 2022 Preview Community
のインストールは終わったかだぜ?」
「 👆 [新しいプロジェクトの作成(N)]
をクリックするか、 [Alt] + [N]
キーを打鍵するかしろだぜ」
「 👆 メニューや、ボタンの名前の後ろに 丸かっこに入って アンダースコア(下線)が引かれている英字大文字は
古い言い方で ニーモニック(mnemonic)、 一般的には アクセラレーター キー(Accelerator keys)
と呼ぶもので、
[Alt]
キーを押しながら そのアルファベットのキーを ちょんと押すと クリックしたのと同じ動きをするぜ」
「 👆 [Alt]
というのは オルタネート キー(Alternate key) とか オルト と呼んでるもので、
このキーを押したからといって 何かが起こるわけではないが、別のキーと組み合わせて使うぜ」
「 👆 [Alt] + [N]
キーと言う場合、 オルト キーと N キーを 一緒に押すのではなく……」
「 👆 [Alt]
キーを押しっぱなしにしながら、 [N]
キーを ちょん と押し下げて すぐ 離せだぜ」
「 大阪日本橋の近くに住んでたから こういうことを 一通り教えてくれる コンピューター オタク の先輩が近所にいたけど、
それは 特異 なことで、世の中 そんな人は 近所にはいないのよ 。
世間の人は ネットの切れ端みたいな記事みて プログラムを 断片的に覚えるのよ。
その構造に うらみの根を持って こういう一気通貫の 長い 記事かいてんのよ」
「 👆 C#
、 すべてのプラットフォーム
、 デスクトップ
、 WPF Application
をクリックして [次へ(N)]
をクリックしろだぜ。
ここで、 .NET Framework
と付いてあるのは レガシー(時代遅れ)なんで選ぶなだぜ。付いてないのを選べだぜ」
「 👆 次の画面にも アクセラレーター キー いっぱいついてるな」
「 👆 3点リーダーは ダイアログボックスが ポップアップしてくる印だぜ」
「 👆 また、テキストボックスに これから文字を入力しようというとき、テキストボックスは フォーカス(Focus)
を持っていると言うぜ」
「 👆 [Tab]
キーを打鍵すると、フォーカスは 次の クリックできるところへ飛ぶぜ。 これを特に専門用語は無いが、 タブ オーダー(Tab Order)
とか呼ぶぜ」
「 👆 [Shift] - [Tab]
キーを打鍵すると 逆回りだぜ」
「 👆 [プロジェクト名]
は WpfExerciseDustPaperOnDesktop
にでもしろだぜ。
[場所]
はデフォルトのままでもいい。わたしは C\GitHub
というフォルダーを作って そこに置いてるけど」
「 👆 わたしも知らんけど 今年の11月ぐらいには出てくるらしい .NET 6.0(プレビュー)
にしよかな」
「 👆 開発画面が出てきたぜ。 前の Visual Studio 2019
とパッと見た感じ 変わってない感じ」
「 👆 プロジェクト名を後で変えたくなったときは、 右上の ソリューション エクスプローラーの ツリー構造の2段目を右クリックして
[名前の変更(M)]
を選ぶか、または [F2]
キーを打鍵すれば変更できるんだが……」
「 👆 [F2]
は ファンクション キー(Function Key) だな」
「 ファンクション キーも 本来は 好きに使っていい ショートカットのためのキー だったと思うんだが、
Windows になると F1
は ヘルプだとか F2
は名前変えるだとか、 使い方が固定されてきた」
「 慣習を引き継ぐのは 古い世代に任せて、 いち から コンピューターはどうあるべきか 今の文化を 見直そう、という動きがあっても いいと思ったら
デスクトップPC 丸ごと無視して みな スマホ の方に行ってしまった」
「 👆 自動で変更してくれない 残り が どこかにあったりするんで、
詳しくないうちは プロジェクト名を付け間違えたら 最初からやり直せだぜ」
「 👇 WPF を開発するのに 何かフレームワークを入れておかないと ぜんぜんできないんで、フレームワークは Livet を選ぶぜ」
「 👆 [ツール] - [NuGet パッケージ マネージャー] - [ソリューション NuGet パッケージの管理]
をクリックしろだぜ」
「 👆 [参照]
タブをクリックして検索ボックスに Livet
と打鍵し、 LivetCask
を選んで プロジェクトの横のチェックボックスをクリックして インストール
しろだぜ」
「 インストールが終わったら NuGet のページは閉じろだぜ」
「 👆 今 こんな感じの画面かも知れないな。
このままでは 使いにくいかも知れないから……」
📖 WPF開発してるときの、画面の整え方をまとめようぜ(^~^)
「 👆 画面を整える方法を まとめたんで 上の記事を読めだぜ」
「 👆 ソリューション エクスプローラーの2つ目ぐらいにある プロジェクトを右クリック、
[追加] - [新しいフォルダー]
をクリックしろだぜ」
「 👆 名前を入れろだぜ。
ここでは ViewModels
と Views
という名前の2つのフォルダーを作れだぜ」
「 👆 名前を入れ間違えたら、 [F2]
キーを打鍵すれば リネームできるぜ」
「 まだ何もプログラム書いてないが、最初から ウィンドウを表示するぐらいのことはできる。やってみようぜ」
「 👆 標準ツールバーの 右向いてる緑色の三角形みたいなボタンをクリックしてみろだぜ」
「 👆 Visual Studio のウィンドウのレイアウトが がらりと変わって、 なんか 白いウィンドウが出てきただろ。
じゃ、その 出てきた白いウィンドウを 閉じろだぜ」
「 👆 ソリューション エクスプローラーの プロジェクト名を右クリックして エクスプローラーでフォルダーを開く
をクリック」
「 👆 Windows ファイル エクスプローラー
が出てくるので、 bin
フォルダーの中を開けていけだぜ」
「 👆 .exe
ファイルができてるから、ダブルクリックしろだぜ」
「 👆 じゃあ さっきの 白いウィンドウが出てきたな。 これが 実行ファイル の作り方の基本だぜ」
「 👆 ソリューション エクスプローラー上で MainWindow.xaml
をダブルクリックしろだぜ。
デザイナーが出てくるな」
「 👆 XAML
の方の <Window
という要素名を狙って マウスカーソルでクリックしろだぜ。
プロパティが出てくるな」
「 👆 プロパティ ペーンの [雷マーク] - [カテゴリ] - [外観] - [WindowStyleのドロップダウンリストの三角ボタン] - [None]
を選べだぜ」
「 👆 すると XAML の方に WindowStyle="None"
が付いたな」
「 👆 こんな感じに覚えておけだぜ。
プロパティ ペーンで設定したものは XAML のタグのアトリビュートに付く、ぐらいの規則性に気づけだぜ。
アトリビュートに どんな風に付くかは、なんかシンプルに付くと思っておけだぜ、今のところは」
「 慣れてきたら XAML のテキストを直接 編集しろってことなのかしら」
「 XAMLはテキストなんで、コピー 貼り付け も利くしな。規則性の分かってきたプログラマーは XAML 直接編集だよな」
「 このステップの話しは むずかしいんで、 読み飛ばして 構わないぜ。必要になったら読めばいい」
「 XML(エックス・エム・エル)の読み方を簡単に説明するぜ」
「 <
と >
で挟まれたものを タグ と呼んでいるのは分かると思うが、うしろの括弧に /
(スラッシュ)が付いている />
を持つものは、
なんか 単独なんだな、と思っておけだぜ」
「 👆 要素 (Element;エレメント) は 開きタグ と 閉じタグ で作れるやつもあるぜ。
どう使い分けるのかというと……」
「 👆 閉じタグ、開きタグに分かれている方は、間に 子要素 などを挟めるわけだぜ。
何も挟まない要素は 単独タグ が使いやすいぜ」
「 👆 また 単独タグ、または 開きタグは、 属性名="属性値"
という形で 名前と値(Value;あたい)のペアを持てるぜ。
これを アトリビュート(属性;ぞくせい)と呼ぶぜ」
「 👆 開きタグ と 閉じタグの間に テキスト をそのまま書いてもOKだぜ」
「 このステップの話しは むずかしいんで、 読み飛ばして 構わないぜ。必要になったら読めばいい」
「 👆 XAML(ザムル)は、 XML に追加ルールを設けたものだぜ。簡単に説明するぜ」
「 👆 XML では、 アトリビュートの値に 要素を入れる、みたいなことはできず、
<FullName>なんとか
と 三角形の括弧を エスケープ して入れるぐらいだったんだが、 XAML では そこは……」
「 👆 こんな書き方で アトリビュートに要素を入れるのを許容しよう、という 運用 をしてるわけだぜ。
なるほど 確かに XML の表現力が 爆上げ してるぜ。歓迎だぜ」
「 👆 上図の Game.Series
プロパティは、 Character要素のプロパティではなくて、
親要素の Game のプロパティを使ってる、みたいな 書き方も XMLに追加ルールで運用される。
これも 今は便利さが分からないと思うが、使いようがあって、 XML の表現力が 爆上げ してるぜ。歓迎だぜ」
「 👆 ここで!
タブに書いてある ファイル名の末尾に注目してくれだぜ」
「 *
(アスタリスク)だぜ。
ファイル名のうしろに *
が付いているファイルは、まだ保存されていません、という印だぜ」
「 👆 すべて保存
ボタンをクリックして すべてのファイルを保存するか……」
「 [Ctrl]
キーと [Shift]
キーを押しっぱなしにしながら [S]
キーを ちょんと 軽く打鍵しろだぜ」
「 これを [Ctrl] + [Shift] + [S]
とコマンド表記することがあるぜ。
3つのキーを 同時押し しようとすると プログラムに s
の字を書きこんで できねーっ てなるんで、
[Ctrl]
、[Shift]
、 [Alt]
キーは 他のキーと一緒に押さなければ (基本的に) 何も起こらないようになってるんだぜ」
「 Shiftキーを5連打してみなさいよ。 びっくりして 椅子から転げ落ちるから」
「 👆 ファイルを1つ保存するボタンをクリックして アクティブなファイルを……、アクティブなファイルって何かって説明するのが難しいよな。
今 キーボードの a
を押したら a
の字が打ち込まれるようなテキスト・ファイルとかのことだぜ。
アクティブなファイルだけ 保存されるぜ」
「 代わりに [Ctrl] + [S]
キーでも保存できるぜ」
「 あっ、 2021年にもなって フロッピー ディスク💾 のアイコンだぜ!」
「 タイトルバーが消えたぜ。 あと もともと見えてないが ウィンドウの枠が消えたぜ。
昔は ウィンドウに 太い枠が有ったんだぜ」
「 残っている部分は クライアント領域 と呼ぶぜ。 変な名前だが、
Windows ME ぐらいの頃から クライアント領域 って呼んでたから ずっと昔から クライアント領域って名前なんだぜ」
「 👆 閉じるボタン 無くなっちゃったんで、タスク バーのアイコンを右クリックして ウィンドウを閉じる
を選んでくれだぜ」
「 👆 プロパティ ペーンで AllowsTransparency
にチェックを入れろだぜ」
「 👆 ブラシ
カテゴリの Background
に #00000000
を入れろだぜ。 #00xxxxxx
で
不透明度(Opacity)あるいはアルファ値が 00
、つまり 透明という意味だぜ」
「 👆 ほら クライアント領域が透明になったぜ。
なんか 1 pixel ぐらいの黒い枠線が残ってんな……」
「 実行してみると 黒い線も見えないぜ。 透明で、どこにあるかも見えないウィンドウだぜ」
「 👆 ウィンドウのリサイズ用の境界線かも知らん。 ResizeMode="NoResize"
を付けてくれだぜ」
「 デバッグ実行時に 1 pixel の黒い枠線は見えるぜ。何も変わらないぜ」
「 グリッド デザインは 初心者には早かったのでは……、まあいいか やったろ」
📖 WPFのGridとかStackPanelとかWrapPanelって何なんだぜ(^~^)?
「 👆 グリッドって何か、の説明は 上の記事を読んできてくれだぜ」
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>
「 👆 XAML をコピー貼り付けするだけで 丸とか 四角とか置けるから 試してくれだぜ」
「 マウスカーソルで テキストを選んで [Ctrl] + [C]
、
貼り付けたいところに [Ctrl] + [V]
で貼り付け」
「 Web系プログラマーでなければ 知らないから関係ないもしれないが、
HTML だと タグの中にタグを入れて、またその中にタグを入れて…… と
入れ子が激しいんだが、WPFの グリッド レイアウトだと 入れ子は 少し緩和されるぜ」
<!-- ちらしっぽいメッセージを書きましょう -->
<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>
「 👆 XAML をコピー貼り付けするだけで テキストを置けるから 試してくれだぜ」
「 タイトルバーがなくなったんで
ウィンドウをつかむところがなくなって ウィンドウを移動できなくなったし、
ウィンドウの枠がなくなったんで ウィンドウの端っこをつかんで リサイズできなくなったし、
最小化、最大化、閉じるボタンも無くなったんで、
これら 自力実装しなくちゃ いけないな」
「 黙って Windows のルックスをそのまま使って 生産性の向上 に注力したらいいのに」
「 最初の この演習は、
ウィンドウに最初から付いているものを 消して、 自力で再実装することだぜ」
<!-- ここにボタンを並べてください -->
<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>
「 👆 XAML をコピー貼り付けするだけで ボタンを置けるから 試してくれだぜ」
「 最大化したときの見え方とか、テストしたいだろ。
ボタンに機能が入ってないと不便だよな。付けようぜ?」
「 👆 デザイナーで 最小ボタンをクリック、 プロパティ ペーンで 雷マーク をクリックして Click
の右横のテキストボックスを
ダブルクリックしろだぜ。 最小ボタンをダブルクリックしても同じだけど」
「 👆 コードの画面に飛ぶぜ。 Button_Click
とか書かれたコードができているが、これが スケルトン だぜ。
スケルトンというのは、 ここにコードを書け っていう 中身が空っぽなものだぜ」
「 👆 ファイル名のうしろに *
(アスタリスク)が付いているのは、まだ 保存されていないという印だぜ」
「 👆 すべて保存
ボタンをクリックするか、 [Ctrl] + [Shift] + [S]
キーをクリックしろだぜ。
保存されてないファイル全部保存されるぜ。
ファイルを1つずつ保存したいときは [Ctrl] + [S]
だぜ。まあ試せ」
「 特に 2000年 '00年代のデジタルなイラストレーターは 保存
ボタン押し忘れて 1日の作業が消えるし、
特に '00年代のデジタルなイラストレーターは ハードディスクのバックアップを取ってないから 生涯の全作品が消えるのよ」
「 2020年代になると いい感じの企業の会社員は どこかにある データセンターのサーバーに ログインしてから作業するんで
データは サーバー側のディスクに取ってるよな。 会社がバックアップを取ってくれてるぜ。
目の前にある 貸与のローカルPCにデータ置いてないよな」
「 👆 Button_Click
のところで右クリックして、 名前の変更
を選んでくれだぜ」
「 👆 MinimizedButton_Click
に変えて [Enter]
キーを打鍵(だけん;タップ)してくれだぜ」
「 👆 参照箇所も併せて変わってくれるので 修正の手間要らずだぜ」
「 👆 以下同様で、 MinimizedButton_Click
、 NormalButton_Click
、 MaximizedButton_Click
、 CloseButton_Click
の
4つのスケルトンを用意してくれだぜ」
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();
}
「 👆 すでに 最大化 してるんだったら [最大化]
ボタンなんか見えない方がいいし……」
「 👆 すでに 元のサイズに戻っているのなら、元のサイズに戻すボタンなんか見えない方がいいぜ」
「 プログラマーが意識したいのは
機能があるものは、その機能を持っているように見えること、
機能をもっていないものは、その機能をもっていないように見えること、
機能を持っているように見えるものは、その機能を持っていること、
機能を持っていないように見えるものは、その機能を持っていないこと だぜ」
「 通常のサイズのとき 元のサイズに戻すボタンを 見えなくして、
最大化のサイズのときは 最大化ボタンを 見えなくしてくれだぜ」
「 じゃあ まず 良くない書き方の例から説明するぜ。
そのあとで 良い書き方の例を説明する」
<!-- 元のサイズに戻すボタンです -->
<Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click">
</Button>
「 👆 今、ボタンは シンプルに書けてるんだが、これを 複雑に書いていってみるぜ。お見せしよう」
<!-- 元のサイズに戻すボタンです -->
<Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click">
<Button.Template>
<ControlTemplate TargetType="Button">
</ControlTemplate>
</Button.Template>
</Button>
「 👆 Button が Template というプロパティを持っているんで、そこに ControlTemplate をセットするには、
上記みたいな書き方をするのが一番簡単なんだが、この書き方は XAML が読みにくくなるんだぜ。続けるぜ」
<!-- 元のサイズに戻すボタンです -->
<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>
「 👆 ニュートラルな状態での 元のサイズに戻す
ボタンと、
ウィンドウのサイズが ニュートラル なときの 元のサイズに戻す
ボタンの場所を無くす設定だぜ」
「 すっきりしてた XAML が、とたんに ごちゃごちゃ し出したわねぇ」
「 確かに 普通のサイズに戻す
ボタンは 場所が無くなってるぜ」
「 そこで リソース ディクショナリー を使うやり方を、初心者こそ 早く覚えようぜ」
MainWindow.xaml:
<!-- このウィンドウでだけ使うリソースを定義します -->
<Window.Resources>
</Window.Resources>
「 👆 Window要素の冒頭らへんに <Window.Resources>
子要素を置こうぜ」
「 👆 そして さっきの <ControlTemplate>
要素を カット&ペースト」
「 👆 上図の位置で k
を入力して 候補から Key (x)
を選択」
「 👆 "
(ダブルクォーテーション )の閉じるとこまで 自動で補完してくれるから、その中を書けばいいんだが、
ここに何を書くかというと まあ 先頭が小文字英字 の例が多いぐらいで 任意(にんい)の名前だぜ」
<!-- このウィンドウでだけ使うリソースを定義します -->
<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>
「 👆 キーの値は normalButton
とかにしとこうぜ」
Template="{StaticResource }"
「 👆 上記みたいな感じで キータイピングしていると 入力候補が出てくるんで、 onrmalButton
を選べだぜ。
入力候補出ないな? と思ったら [Ctrl] + [Space]
キーを打鍵(だけん;タップ)しろだぜ」
<!-- 元のサイズに戻すボタンです -->
<Button Width="80" Height="30" Content="元サイズ戻す" Click="NormalButton_Click"
Template="{StaticResource normalButton}"/>
「 👆 これで さっきと同じ働きもするし、 XAMLも読みやすい 良い書き方だぜ」
「 コーディングの初心者のときに コーディング スキルの高い技を持っていたいよな」
「 低いコーディング スキルと、ものすごい熱意で 重量級のコード書くのも 誰もが通るところだから それはそれで構わないのよ。
それを引き継ぐことになって メンテナンスするのも 構わないのよ。
飛伝のタレで メンテナンスしてはいけなくなって 継承を続けることが伝統になるのが 嫌なだけで」
<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}"/>
「 👆 Button
タグには Widh="80"
とか Content="元サイズ戻す"
といったアトリビュートが残っているな?」
「 👆 ControlTemplate
タグの方にも、 Widh="80"
とか Content="元サイズ戻す"
とか、おんなじ値のアトリビュートがあるな?」
「 👆 Button
の Width="80"
と、 ControlTemplate
の Widh="80"
だったら、どっちを使ってるんだぜ?」
「 Button
の方は無視して ControlTemplate
の方を使ってるぜ」
「 ControlTemplate
が ぶら下がったら、元のタグの方のレイアウトは すっかり忘れてしまって
ごっそり ControlTemplate
の方が使われると思えだぜ」
「 じゃあ Button
の方の Width="80"
とかは使ってないんだったら 消したらいいんじゃないか?」
「 どっちかと言うと…… ControlTemplate
の方の Width="80"
を消したいんだぜ。
Button
に Width="80"
と指定したら、 ControlTemplate
の方の Width
も 80 になってほしい」
「 👆 ControlTemplate
って名前をしているが、こういうの テンプレート (Template) という概念なんだぜ。
テンプレートって何かというと 穴あき定規 なんだが」
「 おんなじ物 何回も使う、っていうことだぜ。
そのとき 一部分だけ ちょっと変えて使いたい なんてことも よくあるわけだぜ」
「 👆 Width="
の始まりのダブルクォーテーションのすぐ右から {B
と打鍵し始めろだぜ。
インテリセンス(IntelliSense)が出てくる……、この入力候補が出てくるやつのこと インテリセンスとか呼んでるやついるのかだぜ?」
「 Visual Studio は インテリセンス が出てくるのが自慢なんで、 Visual Studio を使うんだったら積極的にインテリセンスを使えだぜ。
なんなら [Ctrl] + [Space]
で こっちから インテリセンスを呼び出せるぜ」
「 Bind
とか打鍵すれば そこで書ける バインドの種類が一覧されるんで、 TemplateBinding
を選べだぜ。
テンプレートで使うバインディングだから TemplateBinding
なんだろ、簡単だろ」
「 そして 半角スペース1個空ければ また インテリセンスが出てくるぜ。
これは テンプレートのタグに TargetType="Button"
って書いてるから Button と知ってて出てくるんだけど」
「 さらに W
って打てだぜ。 Width
(ウィトゥス;横幅)が出てくるぜ。
これ、 Button の Width
だぜ」
<Rectangle Width="{TemplateBinding Width}" Height="30"
Stroke="#FF000000" StrokeThickness="0.5"
Fill="#FFDDDDDD"/>
「 👆 これで ControlTemplate
から Width="80"
が消えて、 Button
の方の Width="80"
になったんだぜ。
これが バインディング」
<!-- このウィンドウでだけ使うリソースを定義します -->
<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>
「 Button は BorderThickness 持ってるかと思ったんだが インテリセンスに出てこなかった。さっぱり分かんね」
「 [元のサイズに戻す]
ボタンと、 [最大化]
ボタンの違いって、何だぜ?」
「 👆 [元のサイズに戻す]
ボタンは ウィンドウサイズが normal
のときは 場所から消えていて、
[最大化]
ボタンは ウィンドウサイズが maximized
のときに 場所から消えてることだぜ」
「 👆 しかし 違うところが 少しだけだったら そこだけ外にだしたいよな。
<Button.Style>
、 <Style>
、 <Style.Triggers>
の合わせ技で 外に出せるようだぜ」
「 なんか めんどくさいことに 足を踏み込んでしまったかだぜ」
<!-- ウィンドウを [元のサイズに戻す]ボタン -->
<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>
「 👆 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>
「 👆 DataTrigger を [Ctrl] + [X]
キーで切り取って……」
「 👆 normalButton
だけ残して maximizedButton
の方をバッサリ消して……」
「 👆 Buttonタグの方の maximizedButton
と書いているところを normalButton
に書き直せば OK だぜ」
「 なんか XAML の グリッド レイアウトを書くところが ぐちゃっと しちゃったわねぇ」
「 その ぐちゃっと している <Style>
タグを、 <Window.Resources>
タグの中へ 持っていけないのかだぜ?」
「 やってみるか……。 WPF、 なんか こういうところ ベスト プラクティスは どうすればいいんだろうな」
「 👆 コードの 左横にある マイナス印のボタン、 折りたたみボタン
って言うんだが 使うぜ」
<!-- [元のサイズに戻す]ボタンのスタイル -->
<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>
「 👆 <Button>
タグから <Style>
タグを切り取ったものを [Ctrl] + [V]
で貼り付けて、
[元のサイズに戻す]
ボタンのスタイルの方には キー名 x:Key="normalWindowSizeButton"
を付けて、
[最大化]
ボタンのスタイルの方には キー名 x:Key="maximizedButton"
を付けるぜ」
<!-- ウィンドウを [元のサイズに戻す]ボタン -->
<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>
から <Style>
タグを切り取って 持っていっちゃったんで、
代わりに Style=""
というアトリビュートを使って キー名 を指定しておけだぜ」
「 WPFは、こんな めんどくさい 切った貼った をしなくちゃならないのかだぜ?」
「 自分がやらなくても、他人はやってるから、こういうコードも 読めなくちゃいけないのよ」
「 👆 ボタンに マウスカーソルが重なっても ボタンに色がついたり、何か見た目に変化が無いの、
押せるのかどうか 分かりづらいぜ」
「 👆 ControlTemplate
を使ったから、もともと ボタンに付いていた機能が消えたんだな。
自力実装する必要があるぜ。説明しよう」
「 👆 [元のサイズに戻す]
ボタンのルックスを作っている 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>
「 👆 Setter
タグは、名前の付いているエレメントのプロパティを変えれるんで、それを使うぜ。
<Trigger Property="IsMouseOver" Value="True">
は、 もしも マウスが重なっていたら、ぐらいの意味だぜ」
「 👆 マウスカーソルが重なると ボタンに色が付く仕掛けを 自作 したわけだぜ」
参考記事:📖 [WPF] Templateで見た目を変えつつStyleとTriggerでMouseOver等のときの色を変える
「 IsMouseOver
以外には、どんなトリガーがあるんだぜ?」
「 それを調べる方法が 分からないんだぜ。自分流のやり方はあるけど カンペキな答えになってない。説明しよう」
「 👆 Rectangle
というタグの名前のところを右クリックして、 [定義へ移動(G)]
をクリックしろだぜ」
「 👆 Rectangle
のソースの 概要だけ見えるんだが、さらに Sharp
を右クリックしろだぜ」
「 👆 Sharp
のソースの 概要だけ見えるんだが、さらに FrameworkElement
を右クリックして [定義へ移動(G)]
をクリックしろだぜ」
「 👆 FrameworkElement
のソースの 概要だけ見えるんだが、さらに IInputElement
を右クリックして [定義へ移動(G)]
をクリックしろだぜ」
「 👆 IInputElement
のソースの 概要だけ見えるんだが、ここに IsMouseOver
の名前が見えるな」
「 多分、WPF では DependencyProperty
という仕組みが裏で働いていて、これが働いているから、 Property="名前"
の形に書けると思うんだぜ。
そこから わたしは慣習に従って IsMouseOverProperty
といった名前のプロパティを探すぜ」
「 👆 こんどは FrameworkElement
の UIElement
を右クリックして [定義へ移動(G)]
をクリックしろだぜ」
「 👆 UIElement
のソースの 概要だけ見えるんだが……」
「 👆 ドキュメントはあるんだけど、欲しいのと違うのよねえ」
「 ボタンを押したときは、ボタンが押したような見た目になってほしいよな」
「 マウスボタンが重なったときみたいに、 Rectangleタグに名前を付けて、 マウスボタンを押したというトリガーの中に
Setterタグを置いて Strokeプロパティや、Fillプロパティの色を塗ったらいいんじゃないの?」
「 その、 マウスのボタンを押したトリガー の名前が分からん。 [Ctrl] + [Space]
を打鍵しても インテリセンスが出てきてくれないぜ? 」
「 Style のトリガーに マウスのボタンを押した
とか無いのかも知らん。」
📖 WPF: Change background color of border on left mouse button down
「 👆 Button には IsPressed があるらしいんだが、 Rectangle には無いんだぜ」
「 じゃあ Button の IsPressed を使えばいいのでは?」
<!--
マウス ボタンを押下したときに、背景色を暗くします
-->
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="normalButtonRect" Property="Stroke" Value="White"/>
<Setter TargetName="normalButtonRect" Property="Fill" Value="DarkGray"/>
</Trigger>
「 👆 マウス ボタンを押下すると 四角形の背景色が 灰色になることで、 ボタンを押したという感じを 視覚的に表現だぜ」
「 [最小化]
ボタンと、 [閉じる]
ボタンは 押下すると 水色っぽい色になるのに、
[元のサイズに戻す]
ボタンと、 [最大化]
ボタンが ボタンを押下すると 灰色になってて イケてないわよ?」
「 1か所自作すると 他の自作していないところ 全部気になるしな」
<!-- ウィンドウの [最小化]ボタン -->
<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}"/>
「 👆 4つのボタンそれぞれに 同じテンプレートを付けようぜ?」
「 この グリッド レイアウト の XAML が 見やすくなるように 脳をフル回転 させてんのね」
「 他人が書いた Template
とか Style
とか、結局
コード書いて 実行してみるまで何が起こるか分からないから、
再利用するために必要な勘が無くて、一から書き直す ことになるよな」
「 圧倒的に 自由自在に WPF を使いこなす底力を上げるしかないぜ。
前担当者のスキルレベルを計れる程度に自分が詳しくなければ、自分に把握できないコードが出てくるぜ」
「 お父ん、タイトルバー無くなったんで マウスでつかむところ無いぜ。
どうやって デスクトップ上で ウィンドウを移動させるんだぜ?」
「 まず、 アプリケーションに マウスが当たってるかどうか の判定をしたいよな」
「 👆 デザインで ちり紙 を選んで 雷マークを選んで MouseDown
の右横のテキストボックスを ダブルクリックしてくれだぜ」
「 👆 コードが出てきて、 Rectangle_MouseDown
というスケルトンができてるな」
「 👆 メソッド名を選択して 右クリックから 名前の変更
で、 DustPaper_MouseDown
という名前に変えてみようぜ?
雰囲気出るな」
private void DustPaper_MouseDown(object sender, MouseButtonEventArgs e)
{
Trace.WriteLine($"マウスボタンを押下しました。 sender.GetType()=[{sender.GetType()}]");
}
「 👆 上記のように1行書き込んでほしいんだが、赤い波線と 豆電球のマークが出ているな。
コンパイル時エラーだぜ」
「 👆 赤い波線は 直せることが多い。 赤い波線にカーソルを合わせて じっとしろだぜ。
近くに豆電球マークが出てきたらクリック、
修正方法、または 要らんことの いずれかが出てくるから今回は using System.Diagnostics;
をクリックしろだぜ」
「 直し方を知っている人しか 使いこなせないわよね 豆電球」
「 慣れてくれば ガチャガチャ をやりだすぜ。 つまり 選んで直ればOK、直らなければ アンドゥ を繰り返すんだぜ」
「 👆 右クリックから デザイナーの表示
で デザイナーへ戻って」
「 👆 MouseDown="DustPaper_MouseDown"
のところを [Ctrl] + [C]
でコピー」
「 👆 他のちり紙にも [Ctrl] + [V]
で貼り付けろだぜ」
「 実行して これで ちり紙の上で マウスクリックすれば 反応があるかというと……」
「 👆 なんか上に文字が乗っていてな。失敗する。思ってるようには反応しないぜ」
「 文字をクリックしたかったのか、紙をクリックしたかったのか 分からんからなあ。
だから Windows のルックスには タイトルバーがあったんだぜ」
📖 WPF マウスクリックイベントを透過WPF マウスクリックイベントを透過
「 👆 文字は 受け取ったマウスダウン イベントを 後景のちり紙に 投げ下げる仕組みが なんかあるみたいよ?」
IsHitTestVisible="False"
「 👆 おお、文字の後ろの四角形に マウスダウンが利いたぜ!」
/// <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}]");
}
「 👆 マウスカーソルのスクリーン座標での位置の取得の仕方は、以前に練習して記事にしてあるんで気になったら参照しろだぜ」
(👆 ウィンドウ外にマウスカーソルが出ても、マウスの押下状態はキャプチャーされるか?)
「 👆 押下したマウスボタンを離した瞬間をウィンドウは知らないのに、マウスボタンが離されていることって いっぱいあるだろ」
「 ポップアップが飛び込んでくるような迷惑行為とか、 移動するオブジェクトの方が マウスカーソルの指しているところから出ていったり」
「 マウスリリースのイベントが ウィンドウ外で起こっても拾うかどうかってことよね。
試してみましょう」
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}]");
}
「 マウスカーソルがウィンドウの範囲外に行ってしまったときのマウスボタンの状態変化は キャプチャーしてくれないのね」
「 👆 マウスカーソルが ウィンドウから出たり 入ったりするとき MouseLeave
や MouseEnter
イベントの通知を
受け取ることができるはずだから、そこで マウスボタンが押されているか 離されているか 調べることにしようぜ?」
「 👆 ViewModels
フォルダーを前に作ってあると思うが……」
「 👆 ViewModels
フォルダーの下に クラスを作ろうぜ?
[ViewModels]フォルダー - [追加] - [クラス]
」
「 👆 ファイル名は MainWindowViewModel
で」
「 👆 作った MainWindowViewModel.cs ファイルのコード画面で 右クリック、 Using の削除と並び替え
を選ぶと」
「 👆 使ってない using 文を消してくれるぜ。すっきりしたな」
「 Go言語と Visual Studio Code の組み合わせなら オートでやってくれるのに」
「 👆 次に手動で namespace に .ViewModels
と打鍵してくれだぜ。
そして class
の左側に public
と打鍵してくれだぜ」
Window タグに:
xmlns:viewModels="clr-namespace:WpfExerciseDustPaperOnDesktop.ViewModels"
Window タグの子要素として:
<!-- このウィンドウに紐づくViewModelです -->
<Window.DataContext>
<viewModels:MainWindowViewModel/>
</Window.DataContext>
「 👆 そのあと 上記のように 2か所追加してくれだぜ。
これで MainWindow.xaml
ファイルと MainWindowViewModel.cs
ファイルは なんか関係あるんだな、
ということが Visual Studio に伝わるんで 便利になるぜ」
namespace WpfExerciseDustPaperOnDesktop.ViewModels
{
using System.Windows;
public class MainWindowViewModel
{
/// <summary>
/// マウスボタンを押下した地点です。スクリーン座標です
/// </summary>
public Point StartPoint { get; set; }
}
}
var viewModel = this.DataContext as MainWindowViewModel;
viewModel.StartPoint = coord;
「 👆 2行書き足してくれだぜ。 赤い波線のとこ エラーなんだが」
「 👆 豆電球をクリックして
using WpfExerciseDustPaperOnDesktop.ViewModels;
を選んで 修正してくれだぜ」
「 コーディングして疲れただろ、動かして 書いたコードが何してるか 見てみようぜ?」
「 👆 viewModel.StartPoint = coord;
と書いた行の テキストエディターの左側の端っこの 灰色のところをクリックしてくれだぜ」
「 👆 じゃ、 画面上の方の 緑色の右向きの三角形のあたりをクリックして デバッグ実行してみようぜ?」
「 制御(せいぎょ) が ブレークポイントで止まったんだぜ」
「 👆 StartPoint
にカーソルを合わせろだぜ。 0, 0 っていう数が 出てくるぜ」
「 👆 左側の三角形をクリックすれば、これが x 座標、 y 座標 ってことが分かるな。まだ 0 が入ってるぜ」
「 👆 coord
も同様だぜ。 出てくるボタン押しまくって自習しろだぜ」
「 👆 デバッグ ツール バーの [ステップ オーバー]
をクリックしろだぜ。 F10
キーを打鍵しても同じ」
「 👆 StartPoint
の中身が変わったな。1行実行されたんだぜ」
「 こういう 数が格納されてるやつ 変数(へんすう) というが、変数の中身は確認できることは分かったな。
いったん ちり紙を閉じろだぜ」
「 👆 MouseMove
イベントの ハンドラ も付けといてくれだぜ」
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;
}
}
「 👆 やったぜ! デスクトップ上で ちり紙を ドラッグ&ドロップすることが できるようになったぜ!」
「 👆 この かっこわるいアイコンは なんとかならんのかだぜ?」
📖 方法: アプリケーション アイコンを指定する (Visual Basic、C#)
「 👆 ソリューション エクスプローラー から プロジェクトを右クリックして、プロパティ
をクリック」
「 👆 [アプリケーション] - [リソース] - [参照...]
をクリックして アイコン ファイルを選べば OK だぜ。
ただ、どうやって アイコン(.ico
)ファイルを作るんだ、という話しはある」
「 1つの .ico
ファイルに 小さなアイコン、大きなアイコン と複数 入ってるから、ただの画像じゃないのよ」
「 👆 まどのもり に アイコンを作る無料のエディターとか あるけど、海外製で とっつきにくいのよね」
「 👆 あれっ インターフェースが とっつきやすくなってる!」
「 👆 今まで ずっと [ソリューション構成]
ドロップダウンリストが Debug
のまま 実行してたと思う」
「 👆 ここから Release
(リリース)に切り替えることができるぜ。
初めて アプリケーションを作ったばかりで 使い込んでいない今の段階では なんか Release モードにしたからといって 嬉しいことは無いと思うぜ」
「 企業になると 〇〇社様向けリリース
とか納品先によって 成果物を分けたり、
〇〇製品(2019年春)
、 〇〇製品(2021年夏)
といった感じで 製品を分けたり、
〇〇社様向け_〇〇製品(2021年夏)_Debug
とか合体して 枝分かれが爆発して 大変な行数になる」
「 コンピューター将棋だと Learning
モードとか あったかな」
「 👆 じゃあ Debug
とか Release
とかは 初期設定で2個用意されてるだけで 違いはないのか?」
「 違いはある。 むしろ Release
モードのこと よく分かってなければ Debug
モードのまま配布した方が
開発中のコードと同じ動きをするぜ。
限界の環境の中では、誰もメンテナンスしていない リリースモード を選ぶよりは、達人は Debug
モードのまま リリースする」
「 👆 ブレークポイント を無効にして 実行するなら [デバッグの続行]
、
Release
モードだけど やっぱ ブレークポイント 使いたい、デバッグしたい というときは [マイ コードのみ]を無効にして続行
を選べだぜ」
「 Release
モードを デバッグしたいときって もちろん あるのよ」
「 👆 おっ ブレークポイント が無視されてるぜ。 重要な機能なんじゃないのか これ?」
「 デバッグモードで配布して ブレークポイントで止まってたら いやだしな」
「 👆 ソリューション エクスプローラー から プロジェクト名を右クリックして
プロパティ
をクリックしてくれだぜ」
「 👆 [ビルド] - [出力]
とクリックしてくれだぜ。 なんか bin\
と書いているのが分かれば OK だぜ。
[×]
印をクリックして プロパティは閉じてくれだぜ」
「 👆 続いて ソリューション エクスプローラー から プロジェクト名を右クリックして
エクスプローラーでフォルダーを開く
をクリックしてくれだぜ」
「 👆 .exe
ファイルができてるから、ダブルクリックしてくれだぜ」
「 👆 作った WPF アプリケーションを配布するときは、このフォルダーの中身を全部 渡せだぜ。
もっと 大がかりなアプリケーションになると、 別のフォルダーと連携したりするんで、大変だが、
この演習課題ぐらいの規模なら フォルダー1つだぜ」
「 Rust言語なら .exe ファイル1つに全部かためてくれるのに、 WPFは もっさりしてるわねぇ」
「 標準ツールバー
で、 ソリューション プラットフォーム
というのを 選べるんだが、
Any CPU にしとけば 32bit CPU
でも 64bit CPU
でも どちらでも動くから、 PC(パソコン)
では ふつうの選択肢だぜ」
「 また、 32bit CPU のことを x86
と よく呼ぶぜ。 Any CPU にしておくと x86
のプログラムとしてインストールされるぜ」
「 これを 64bit CPU でしか動けなくする のが、 x64 という設定だぜ。
なんで そんな不便なことをするのかというと、ゲーム機とか 32bit に対応する用意がないマシンで動かすときのためだな」
「 Cドライブの下の Program Files
フォルダーも、 64bit CPU か、 32bit CPU かで分かれているな。
x86
と書いてあるのは 今では 32bit CPU でしか動かないのではなく、 32bit CPU でも動く 64bit CPU のアプリ
ぐらいに思っておけだぜ」
「 👆 Debug
を Any CPU
にして、 Release
を x64
にするとか、分けることもできるぜ。
というか、分かれているんだぜ。 だから Debug
の分と Release
の分、両方 設定しないといけないぜ」
「 👆 [アクティブ ソリューション プラットフォーム]ドロップダウンリスト
から <新規作成...>
を選べだぜ」
「 👆 で、今までに Any CPU
にいろんな設定をしてあるだろうから、それを引き継いで 新しく作ろうぜ、という画面だぜ。
ここで」
「 👆 分かりにくいんだが、親子関係になっていて、 Debug
の x64
は こんなテーブルですよ、という表示になっているぜ。
WpfExerciseDustPaperOnDesktop
プロジェクトの Debug
構成では プラットフォームは x64
ですよ、と書いてあるんだぜ」
「 👆 これで Debug
モードでは、 x64
専用の実行ファイルが作られるぜ。
今どき 32bit CPU で動くことまで考えておかなければいけないケースは、ふつうは、無いから x64 専用でいいだろ」
「 👆 ちり紙 を すべてのアプリの一覧に並べるには どうやったらいいんだぜ?」
「 👆 Cドライブの下の Program Files
を開けてくれだぜ」
「 👆 [ホーム] - [新しいフォルダー]
をクリックしてくれだぜ」
「 👆 なんか フォルダー名に 半角スペース含めるの 違和感あるんだが、周りに雰囲気を揃えた感じの 被らなさそうな名前を付けてくれだぜ」
「 👆 .exe
が入っているフォルダーを 左に、
Program Files
の下に作ったフォルダーを開けて 右に 見えるよう ファイル エクスプローラー を並べたあと、
コピーしたいフォルダーを マウスの右ボタンでクリックして、 マウスカーソルを 右側の ファイル エクスプローラーに移動しろだぜ」
「 👆 コンテキスト メニューが出てくるんで、 [ここにコピー]
をクリック」
「 👆 アクセスが拒否されるが、構わず [続行]
をクリック」
「 👆 フォルダー名を ちょんとクリックして 名前を変えようぜ? dust-paper-on-desktop
とかでどうだぜ?」
「 👆 dust-paper-on-desktop
フォルダーを開いて .exe
ファイルを右クリック、 [ショートカットの作成]
をクリック」
「 👆 こんなとこにショートカットは作れないが デスクトップに作るのなら大目に見てやろうと コンピューター様が おっしゃっているんで
はい
をクリック」
「 👆 ファイル エクスプローラーから C:\ProgramData\Microsoft\Windows\Start Menu\Programs
へアクセスしろだぜ」
「 👆 ちり紙へのショートカットを右クリック、 ファイル エクスプローラーの タイトルバーの辺りでマウスボタンを離せだぜ」
「 👆 デプロイ(Deploy;ファイルなどの配置、それに関する設定)めんどくさいから インストーラーを作りましょう」
「 Microsoft のドキュメントが推奨する製品 使い方 わけ分からんので 他のを当たろうぜ」
📖 なつかしの Visual Studio Installer(の後継)を現役のVisual Studioで使用する
「 👆 2000年の '00年代は ワケ分からんかったが、 2020年にもなれば 幾分 マシになってるだろうか」
📖 Microsoft Visual Studio Installer Projects 2022
「 👆 ブログ記事読んでたら 2019 用だったんで、探したら 2022 Preview 用のがあったぜ」
「 Visual Studio を使っていると インストール進まないみたいなんで、 Visual Studio は閉じておけだぜ」
「 👆 インストールできたようだな。使ってみるか……。
VSIX
ってのは Visual Studio に機能が付くんだぜ」
「 👆 2行目の プロジェクトではなく、 1行目の ソリューション を右クリック、
[追加] - [新しいプロジェクト]
をクリック」
「 👆 Setup Project
をクリックして [次へ]
」
「 👆 プロジェクト名には 何をインストールするのか分かるような名前を付けろだぜ。
例えば Setup1
を SetupWpfExerciseDustPaperOnDesktop
に変えて [作成]
をクリック」
「 👆 SetupWpfExerciseDustPaperOnDesktop
プロジェクトが増えてんな」
「 👆 この最初の画面は [SetupWpfExerciseDustPaperOnDesktop]プロジェクト
を右クリックして
[View] - [ファイル システム]
をクリックすれば出てくるんで、閉じてしまったときに また出すために 覚えておけだぜ」
「 👆 ソリューション エクスプローラーから [SetupWpfExerciseDustPaperOnDesktop]プロジェクト
を ちょんとクリックすると
プロパティ が表示されるぜ」
「 👆 Author
には作者名を入れろだぜ。ファイルを右クリックしたときのプロパティに出てくる。
Manufacturer
は 製造した団体名でも入れろだぜ。インストール先のディレクトリー名になる。
ProductName
は (インストーラーではなく)インストールしたいアプリの名前を入れろだぜ。
Title
は、どこで使われるんだろうなあ」
「 RemovePreviousVersions
を True にしておくと、古いバージョンがインストールされていれば消してくれるぜ」
「 👆 例えば 古いバージョンがすでにインストールされていて、 RemovePreviousVersions
を True に設定してないと 上書きインストールできないぜ。
Version 番号をこまめに設定してないと意味ない」
「 👆 配布するものは Release
ビルドを使うのが ふつう だぜ。
とはいえ、世の中 ふつうではないとき だってあるので ふつうではないとき は Debug
でビルドして配布することもあるだろう」
「 このあと、うまくいかないこともあるだろうから、そのときは Any CPU
を選んで やり直してくれだぜ」
「 👆 [Application Folder] - [Add] - [プロジェクトの出力]
をクリック」
「 👆 ここで 気にしたいのは 構成
なんだが、何それ? と言うと……」
「 👆 画面 上の方の 標準ツール バーで選ばれているのを (アクティブ)
と呼んでいて、
ここでは 間違えのないように Release x64
を明示的に選ぶかだぜ」
「 上のでっかい Release
とか x64
は これからのインストールで 関係なくて、ここで選んだやつが関係あるのね」
「 👆 これが ユーザーのみなさんの、アプリケーションを入れておくためのフォルダーに デプロイ(配備)したいもの に相当するぜ。
.exe
ファイルとか入ってるフォルダーとかのことだな」
「 👆 そして セットアップのプロジェクトのプロパティで TargetPlatform
が x86
になってるかもしれないから……」
「 ライセンス条項
は、 むずかしいから、 分からん人は 読み飛ばせだぜ」
「 👆 Windows のタスク バーから [スタート]ボタン - [Windows アクセサリ] - [ワードパッド]
をクリック」
「 👆 無限に長い紙みたいなのが出てくるぜ。 これを用意しつつ……」
「 わたしは MITライセンス
を拾ってくるぜ。 お前がどのライセンスを選ぶかは知らん」
「 👆 MITライセンス
の原文を ここから 全文選択、コピーし」
「 👆 <YEAR> <COPYRIGHT HOLDER>
を今の年と 自分の名前に書きかえるぜ。
オープンソースのコミュニティとかの プログラマーの文化的には ここにはコードの作成に直接関わった人間の名前を つらつら書き、 本名が普通だが、
ここは プログラミングの範疇ではなく 法律の範疇なんで お前のことは わたしは知らんので お前の思うようにやれだぜ」
「 👆 保存先は あとで移動させるとして どこでもよくて、
[リッチ テキスト形式 (RTF) (*.rtf)]ファイル
を選択、 LICENSE.rtf
といった名前を付けて [保存]
をクリック」
「 この .rtf
とかいうファイル、 WordPad とかで作れるファイル フォーマットで、 わたしは パーサーを書いたこともあるが 読みにくくて嫌になった。
ぜったい XML ファイルとか HTML/CSS の方が優れていると思うぜ」
「 👆 ライセンスのファイルを添付するために、 [Application Folder] - [Add] - [ファイル]
をクリックしろだぜ」
「 👆 頒布したいプロジェクトの方ではなく、インストーラーのプロジェクトの方にコピーするわけだぜ」
「 👆 次に [WpfExerciseDustPaperOnDesktop]プロジェクト右クリック - [View] - [ユーザー インターフェース]
と進んで」
「 👆 [Install] - [Start] - [ダイアログの追加]
と進めだぜ。
これって インストーラーの出てくる画面の順になってそうだよな」
「 👆 右クリックすると 上へ移動
などで順を変えれるそうだぜ」
「 👆 ライセンス条項
を選んだまま プロパティ ペーンから License File
のドロップダウンリストをクリックして
[(Browse...)]
を選ぶと インストーラーで添付したファイルを選べるようなんだぜ」
「 👆 いろんな種類が選べそうな見た目をしていたが、 テキストファイル(.txt) では ビルド通らなかった。
リッチ テキスト フォーマット(.rtf) にして進めてみるかだぜ」
「 👆 Application Folder
を右クリックして [Add] - [ファイル]
と進めだぜ」
「 👆 まえに アイコン( .icoファイル
)作っただろ。 選べだぜ」
「 👆 どこを右クリックすりゃいいのか よく分かってないが なんか右クリックして 新しいショートカットの作成
をクリックしろだぜ」
「 👆 Application Folder
をダブルクリックしろだぜ」
「 👆 項目の公開 from WpfExerciseDustPaperOnDesktop (Active)
をクリックして [OK]
をクリックしろだぜ」
「 👆 例えば Dust paper on the desktop
とかに変えようぜ」
「 👆 もう片方も同じ名前にしたいんだが、同じ名前のファイルがあるとできないんで ちり紙
とでもしておくぜ」
「 👆 Dust paper on the desktop
を選んで プロパティ ペーン の [Icon]ドロップダウンリスト
から (Browse...)
をクリック」
「 👆 [Application Folder]
をダブルクリック」
「 👆 アイコン ファイル(.ico
) を選んで [OK]
をクリック」
「 👆 ちり紙
ショートカットにも同様に アイコン を付けておいてくれだぜ」
「 👆 Dust paper on the desktop
をマウスでドラッグして User's Programs Menu
フォルダーへマウスでドラッグ&ドロップしろだぜ」
「 👆 ちり紙
をマウスでドラッグして User's Desktop
フォルダーへマウスでドラッグ&ドロップしろだぜ」
「 👆 すると User's Desktop
フォルダーに ちり紙
が入ってるな」
「 👆 すると User's Programs Menu
フォルダーに Dust paper on the desktop
が入ってるな」
「 むしゃくしゃした気分のときに このアプリを実行するんだな」
「 👆 [WpfExerciseDustPaperOnDesktop]
プロジェクトを右クリックして [リビルド]
をクリックしろだぜ」
「 👆 [WpfExerciseDustPaperOnDesktop]プロジェクト
を右クリック、 [エクスプローラーでフォルダーを開く]
をクリック」
「 👆 SetupWpfExerciseDustPaperOnDesktop.msi
ファイルができてるな。ダブルクリックしろだぜ」
「 👆 プロジェクト名ではなく、もっと かっこいい製品名にしなかったのかだぜ」
「 👆 Program Files (x86)
の方ではないことを確認」
「 👆 ほんとにインストールは完了したのかなあ? [閉じる]
ぜ」
「 👆 ほんとに Doujin Soft Circle Grayscale
があるわよ」
「 👆 すべてのアプリケーション一覧に 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
「 👆 他に分かんないところがあれば、自分で調べてくれだぜ」
「 👆 アンインストールするには [Windows スタート]ボタン - [設定]
と進み」
「 👆 [アンインストール]ボタン
が出てくるのでクリック」
「 👆 なんで2回出てくる! [アンインストール]ボタン
をクリック。
すぐには 反映されないが、数秒で 消えるぜ」
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント