WPFでWindow出そうぜ(^~^)?

どふー(^~^) ほぱちゃー(^▽^) 公開下書き

前の話し

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

気の早い人向け

📖 wpf-window-practice - Git Hub に上げたもの
📖 wpf-mutex-practice - Git Hub に上げたもの

今回の話し

ramen-tabero-futsu2.png
「 Window 出そうぜ」

kifuwarabe-futsu.png
「 window.Show() で出せだぜ」

ohkina-hiyoko-futsu2.png
「 コードを書いて動かしてみましょう!」

📖 メインウィンドウから子ウィンドウを開く

ramen-tabero-futsu2.png
「 👆 この記事を参考にしようぜ」

20210901pg1.png

ramen-tabero-futsu2.png
「 👆 最初こんな感じだろ」

        <Button Name="btn0" HorizontalAlignment="Center" 
                    VerticalAlignment="Center" Width="100" Height="50">
            別のウィンドウを開く
        </Button>

ramen-tabero-futsu2.png
「 👆 そこの Gridタグの間に こう書くらしいぜ」

<Window x:Class="WpfWindowPractice.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:WpfWindowPractice"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Button Name="btn0" HorizontalAlignment="Center" 
                    VerticalAlignment="Center" Width="100" Height="50">
            別のウィンドウを開く
        </Button>
    </Grid>
</Window>

ramen-tabero-futsu2.png
「 👆 つまり こう」

20210901pg2.png

ramen-tabero-futsu2.png
「 👆 ウィンドウも追加したった」

        <Button Name="btn0" HorizontalAlignment="Center" 
                    VerticalAlignment="Center" Width="100" Height="50">
            閉じる
        </Button>

ramen-tabero-futsu2.png
「 👆 Gridタグの間に こう書くらしいぜ」

kifuwarabe-futsu.png
「 レイアウトを作っただけで ボタンを押したときとかの 働きのロジックは まだ書いてないな」

20210901pg3a1.png

ramen-tabero-futsu2.png
「 👆 プロパティ ウィンドウのテキストボックスを ダブルクリックしろだぜ」

ramen-tabero-futsu2.png
「 しかし テキストボックスをダブルクリックするとか、そんな ふだんしないようなことを
ユーザーに求めるUIデザインは ダメだと思うぜ。
こんなUIデザインが いっぱいある。 わたしは悲しい」

20210901pg4a1.png

ramen-tabero-futsu2.png
「 👆 スケルトンが作られるな」

20210901pg5a1.png

ramen-tabero-futsu2.png
「 👆 一応説明しておくと、 Buttonタグに Click属性が増えてるぜ」

20210901pg6a1.png

            var win = new Window1();
            win.Show();

ramen-tabero-futsu2.png
「 👆 戻って、2行だけかきたせば サブ ウィンドウが開くようだぜ」

kifuwarabe-futsu.png
「 Window を new して .Show() するだけじゃないか。簡単だろ」

ohkina-hiyoko-futsu2.png
「 ウィンドウが2つになったり、片方が閉じられたら もう片方も閉じたいとか、
やること増えると どんどん 複雑になっていくのよ」

kifuwarabe-futsu.png
「 つら」

20210901pg7a1.png

ramen-tabero-futsu2.png
「 👆 サブ ウィンドウのボタンには 閉じるためのコードを1行だけ書くぜ」

20210901pg8.png

ramen-tabero-futsu2.png
「 👆 メイン ウィンドウの [別のウィンドウを開く] ボタンをクリックすれば、
サブ ウィンドウ が開くぜ」

20210901pg9.png

ramen-tabero-futsu2.png
「 👆 Mutex(ミューテックス;2重起動防止)付いてないんで、
ボタン連打して PCが潰れるまで 窓増やせるぜ」

kifuwarabe-futsu.png
「 ブラクラ(ブラウザ クラッシュ)みたいだな」

二重起動を防止しようぜ?

📖 C#のMutexとは?2つの種類と使用方法を理解しよう!

ramen-tabero-futsu2.png
「 👆 Mutex(ミューテックス;2重起動防止)のことは、この記事を参考にしようぜ。
WPFの機能じゃなくて、C#言語が備えてる Windowsプログラミングという感じのものだぜ」

ohkina-hiyoko-futsu2.png
「 説明が WPF じゃなくて Windows フォーム のものじゃない?」

ramen-tabero-futsu2.png
「 そう! Microsoft Windows のプログラミングに関わると
B で X を使う方法を知りたいのに、A で X を使う方法の記事が 山ほどヒットする!
そして
A で X を使う方法は C だし、 B で X を使う方法は D だぜ!
D が知りたいのに C の記事が出てくる!
Web上の検索は 意味を考えて拾ってくるのではなく 文字で当てて拾ってくるし、
現代の Google は よく検索されているだろう文字列の方を優先して 見つけてくるから D が出てくる!
Microsoft も Google も それを解決できていないところを見ると
インターネット上に大量の情報を 増やすことだけして それを整理することは できてないんだぜ。
だから わたしが 人力で記事を書いて整理している。
わたしは Microsoft や Google の AI技術にはできない 価値の高い記事を書くことを 人力でやっている」

kifuwarabe-futsu.png
「 やっぱ 人力かあ」

📖 WPF:Mainメソッドを書き変えるには?[C#/VB]

ramen-tabero-futsu2.png
「 👆 アットマークIT の記事でも読もうぜ?」

20210903pg13a1.png

ramen-tabero-futsu2.png
「 👆 プログラムが最初に実行されるところのことを エントリーポイント というが、
WPF では App.xaml のところに 自動生成 されるらしく、プログラマーは エントリーポイントに プログラムを書けないぜ」

kifuwarabe-futsu.png
「 わらうwwwwwwwwwwww」

20210903pg14a1.png

ramen-tabero-futsu2.png
「 👆 App.xaml のビルドアクションが アプリケーション定義 になってるから Main 関数が自動生成で上書きされてしまうそうで、
ビルドアクションを ページ にすれば Main 関数の自動生成を止めさせることができるそうだぜ」

ohkina-hiyoko-futsu2.png
「 アプリケーション定義ページ の差異って何なの?」

📖 Application Management Overview

ramen-tabero-futsu2.png
「 👆 アプリケーション クラスを作るのが アプリケーション定義 のようだぜ。
App.xaml を Page にしていいのか、わたしには判断つきかねるぜ。真似せんとこ」

ramen-tabero-futsu2.png
「 Microsoft のドキュメントを読んでも 分からないことが分かるようになることが 少ない。
既に分かってるやつが 答え合わせをするために読むドキュメントだぜ」

📖 Replacing the WPF entry point

ramen-tabero-futsu2.png
「 👆 定番の Stack Overflow も見てみようぜ」

kifuwarabe-futsu.png
「 Application Definition を Page に変える方法は たくさんの記事が出回っているが 望まない結果を得るから
別の方法にしろ、と書いてくれている人がいるぜ」

ramen-tabero-futsu2.png
「 1秒で 分るよな そんなことは。 不具合の発見も考慮して コントロールできていないものを使わないという 考えができてるやつだぜ。
こうやったら できた、で うまく行った、とか やってるやつは 誰にもすくわれない流しそうめんのように 海に流れ出ていってほしい

ohkina-hiyoko-futsu2.png
「 海に栄養がたまるわよ」

20210903pg15a1.png

ramen-tabero-futsu2.png
「 👆 真のプログラマーは こうやって使ってほしいと用意されている方法を使う。 App.xaml の Startup メソッドを実装するのが正解。
テキストボックスを ダブルクリックするという奇行をしろだぜ」

20210903pg17a1.png

ramen-tabero-futsu2.png
「 👆 すると Startup という属性が付いていて、Application_Startup を呼び出します、という紐づけが行われたな。
ここで、 StartupUri という属性ではないことに 気を付けてくれだぜ」

ohkina-hiyoko-futsu2.png
「 隠しテクニックみたいなことをやらせる上に さらに まぎらわし!」

20210903pg18a1.png

ramen-tabero-futsu2.png
「 👆 だから WPFアプリケーションでは Main 関数から始めるのではなく、 App.xaml の Startup 属性に紐づいているメソッドから
始めるのが、 Microsoft から見て そうやってほしい使われ方なのだろう」

kifuwarabe-futsu.png
「 そんなこと Microsoft のドキュメントの どこに書いてるんだぜ?」

📖 Application.Startup Event

ramen-tabero-futsu2.png
「 👆 ここだぜ」

kifuwarabe-futsu.png
「 そんなサイト 誰が読んでるんだぜ?」

ramen-tabero-futsu2.png
「 既に分かっている人が 答え合わせのために読むんだぜ」

20210903pg19.png

using System.Threading;
using System.Windows;

namespace WpfMutexPractice
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// アプリケーションのエントリーポイントです
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            // Mutexの初期所有権が呼び出し元のスレッドに付与されたかどうか
            bool createdNew;

            // Mutex作成
            Mutex mutex = new Mutex(true, "MySampleApplication", out createdNew);

            if (!createdNew)
            {
                // Mutexの初期所有権が付与されなかった場合は、多重起動と判断して終了します
                MessageBox.Show("すでに起動しています。2つ以上同時に起動できません。");
                // Mutex解放
                mutex.Close();
                return;
            }

            try
            {
                // メイン ウィンドウ表示
                var window = new MainWindow();
                window.Show();
            }
            finally
            {
                // Mutex解放
                mutex.ReleaseMutex();
                mutex.Close();
            }
        }
    }
}

📖 C#のMutexとは?2つの種類と使用方法を理解しよう!

ramen-tabero-futsu2.png
「 👆 さっきのサイトのコードをコピペすれば こうだな」

ohkina-hiyoko-futsu2.png
「 それだと App.xaml に StartupUri="MainWindow.xaml" と書いてあるから、2つのコードで ウィンドウを起動しようとしない?」

20210903pg20a1.png

ramen-tabero-futsu2.png
「 👆 StartupUri="MainWindow.xaml" を消すぜ」

ramen-tabero-futsu2.png
「 で、テストしてみると。 あれっ? 多重起動できるぜ?」

kifuwarabe-futsu.png
「 ダメだったのかだぜ」

ohkina-hiyoko-futsu2.png
「 さっきのページには 続きがあるみたいよ?」

📖 WPF で二重起動を防止する

kifuwarabe-futsu.png
「 👆 それより こっちのページを見ろだぜ。 WPF で 二重起動を防止する方法が書いてるぜ」

ramen-tabero-futsu2.png
「 そんなページが有るんなら、最初に見たかったぜ」

20210903pg21a1.png

20210903pg21a1.png

ramen-tabero-futsu2.png
「 👆 Exit 属性も付けろというのは 納得だぜ」

📖 C# WPFで2重起動判定

ramen-tabero-futsu2.png
「 👆 しかし まだ気になることがあったので もっと記事を読むぜ」

kifuwarabe-futsu.png
「 既に起動していたら 2つ目は起動しないだけでなく、
既に起動しているウィンドウを最前面に出すコードかだぜ! ケアが すげえ!」

ohkina-hiyoko-futsu2.png
「 でも C# 使ってるのに 32bit Windows の Win32API ネイティブ メソッド呼び出してるの いけてなくない?」

ramen-tabero-futsu2.png
「 ウィンドウのハンドル A を取得して、そのハンドル A がウィンドウを指すか確認して、
そのウィンドウ A の子ウィンドウまで含めて最後に利用していたウィンドウのハンドル B を取得して、
そのウィンドウ B が可視状態であるかまで確認して、可視であれば、
ウィンドウ B を最大化ウィンドウでも 最小化ウィンドウでもなく ノーマルに表示し、
そして ウィンドウ B を最前面に出す、
ということを やればいいわけだぜ」

kifuwarabe-futsu.png
「 つら」

📖 C# で ウィンドウハンドル を 取得する 方法

ramen-tabero-futsu2.png
「 👆 プログラマーの実践を知ってほしい。 分からなかったら調べろということだぜ。
C# でも ウィンドウのハンドルを取得することはできるらしいぜ。
Win32API とは おさらば しようぜ?」

kifuwarabe-futsu.png
「 お父んに おさらば する権限があるかどうかは プログラミング スキルとは関係ないよな」

ohkina-hiyoko-futsu2.png
「 プログラマーの足を引っ張っているのは 味方のプログラマーですからね。
プログラマーの最大の親友は 敵プログラマーなのよ」

ramen-tabero-futsu2.png
「 ダメだ使えね 次」

📖 [C#][.NET] .NET アプリケーション (WPF/Windows フォーム) で多重起動を禁止し、単一のプロセスで動作させる

ramen-tabero-futsu2.png
「 👆 これは いけそうだが、 バグを盛り込まずに実装できる気がしね」

ohkina-hiyoko-futsu2.png
「 ウィンドウ A を起動したとき、二重起動したら困るんで、
既に起動していた同じプログラムのウィンドウ B が起動しているときは A は起動せず、
既に起動しているウィンドウ B を最前面に出してちょうだいよ。
そのウィンドウが子ウィンドウ C を出していて、最後に触っていたのがそのウィンドウ C だったら、
B ではなく C を最前面に出してよ。
どんなアプリでもよく見かける機能だし、WPFのプログラマーなら、さくっとやってちょうだいよ
Win32API無しで

ramen-tabero-futsu2.png
「 クリボーを超える高さにジャンプできないチビ マリオの気分だぜ。
これは やばいな」

kifuwarabe-futsu.png
「 誰も つまづかないところで つまづくお父ん わらう」

20210903pg23.png

<Application x:Class="WpfMutexPractice.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfMutexPractice"
             StartupUri="MainWindow.xaml"
             Startup="Application_Startup" Exit="Application_Exit">
    <Application.Resources>

    </Application.Resources>
</Application>

ramen-tabero-futsu2.png
「 👆 ひとまず、単に 二重起動しない ミューテックスを使ったアプリのソースを公開するぜ。まず xaml」

20210903pg24.png

using System.Threading;
using System.Windows;

namespace WpfMutexPractice
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// ミューテックス(二重起動防止)作成
        /// </summary>
        private Mutex _mutex = new System.Threading.Mutex(false, "Muzudho's WPF mutex practice");

        /// <summary>
        /// アプリケーションのエントリーポイントです
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            if (!_mutex.WaitOne(0, false))
            {
                // TODO 既に起動しているウィンドウをアクティブ(最前面に表示)します。この機能は難しいので、今回は実装しません

                // 既に起動しているので終了させます
                _mutex.Close();
                _mutex = null;
                this.Shutdown();
            }
        }

        private void Application_Exit(object sender, ExitEventArgs e)
        {
            if (_mutex != null)
            {
                _mutex.ReleaseMutex();
                _mutex.Close();
            }
        }
    }
}

ramen-tabero-futsu2.png
「 👆 次にその C#コード」

kifuwarabe-futsu.png
「 超シンプルだぜ! ミューテックスって簡単だな!」

20210903pg25a1.png

ramen-tabero-futsu2.png
「 👆 プロジェクトを右クリックから、ファイル エクスプローラーを開いてくれだぜ」

20210903pg26a1.png

ramen-tabero-futsu2.png
「 👆 そしたら 📂./bin/Debug/netcoreapp3.1 とフォルダーを下りていってくれだぜ」

20210903pg27a1.png

ramen-tabero-futsu2.png
「 👆 WpfMutexPractice.exe を2回ほど ダブルクリックしても、二重起動しないことを確かめてくれだぜ。
ひとまず そこまで」

20210903pg28.png

ohkina-hiyoko-futsu2.png
「 👆 ウィンドウの後ろに回っている、既に起動しているウィンドウが 最前面にこないでしょ。
これじゃ 製品の品質としては ダメなのよ」

プロセス間通信(IPC)

20210903pg29.png

ramen-tabero-futsu2.png
「 👆 説明を読むと、ローカルPCのどこかにある クラスのインスタンスをバイナリにして投げ込んでおける送信先の住所のようなものが
あるらしいぜ。 URLの書き方は上記の通り」

kifuwarabe-futsu.png
「 チャンネル名と アイテム名を 説明してくれだぜ」

ramen-tabero-futsu2.png
「 チャンネル名は任意だぜ。受け取る相手が知ってる名前にしろだぜ。
例えば .exe ファイルを右クリックしてプロパティを見れば書いているような 製品名 でも入れとけだぜ。
まあ 製品名 が被ってることもあるだろうから、間違って混線することはあるだろうな。
製品名が被ったら それ以外の見分け方の手段も講じなければいけないかもしれないが、今は 良しとしようぜ」

ramen-tabero-futsu2.png
「 アイテム名は任意だぜ。受け取る相手が知ってる名前にしろだぜ。
例えば Move とかいう名前にして、将棋の指し手でも 送り付ければいいんじゃないかな」

namespace WpfIpcPracticeAlice
{
    using System;

    /// <summary>
    /// 名前と本文
    ///
    /// プロセス間通信(IPC) によって複数のプロセスで共有します
    /// </summary>
    public class MessageCard : MarshalByRefObject
    {
        /// <summary>
        /// 名前
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// メッセージ
        /// </summary>
        public string Message { get; private set; }
    }
}

ramen-tabero-futsu2.png
「 👆 試しに 名前と本文だけ持つクラスを作って、チャンネルに送れるか試してみようぜ?」

kifuwarabe-futsu.png
「 System.MarshalByRefObject って型を気にしないオブジェクトだろ。難しいの使ってんな」

📖 .NET - Ipc を使ったプロセス間通信

ramen-tabero-futsu2.png
「 👆 げえっ! レガシー技術かだぜ! 覚える気なくなったぜ」

ohkina-hiyoko-futsu2.png
「 休みは 休んでた方が マシじゃないの?」

ramen-tabero-futsu2.png
「 調べたら .NET core では廃止されてた。
どうすっかな 仕事で使うが プライベートの時間を使ってまで 覚えたくないぜ」

何度でもクリック!→

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

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

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

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

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

ボードとは?

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