としおの読書生活

田舎に住む社会人の読書記録を綴ります。 主に小説や新書の内容紹介と感想を書きます。 読書の他にもワイン、紅茶、パソコン関係などの趣味を詰め込んだブログにしたいです。

タグ:WPF

3753817_s

仕事でWPFアプリケーションの回収をしていたところなんでもシングルスレッドでやってしまっているようなコードがたくさんあり、それが原因で設計どうり動いていないコードがちらほらありました。

そこで本記事ではWPFで重い処理などを非同期処理で実装するべき理由を3つ紹介していきます。


非同期処理で実装する理由


1.画面の描画が行われない


シングルスレッドで全て実装してしまうと重たい処理が走る前に画面の表示を変更する処理をいれているにも関わらず、画面の表示が変更されるのは重たい処理が終わった後になります。

例えば以下のような画面があるとします。

キャプチャ


この画面の「重たい処理」ボタンを押せばボタン上部にStartという文字が現れ、重たい処理終了後にEndという文字が表示されるとしましょう。

このときボタン押下時の処理を以下のように同期処理で実装してしまうとStartという文字が画面には表示されません。

private void Button_Click1(object senderRoutedEventArgs e)
{
test.Content = "Start";

// 重たい処理開始
    for (int i=0i<1000000; ++i)
    {
     for (int j = 0j < 1000000; ++j)
        {
         Math.Sqrt(j);
        }
    }
// 重たい処理終了

    test.Content = "End";
}

こういう場合に重たい処理を以下のように非同期処理で実装していると開始時にはStartという文字が表示され、終了時にはEndという文字が表示されます。

private async void Button_Click1(object senderRoutedEventArgs e)
{
    test.Content = "Start";

    // 重たい処理開始
    await Task.Run(() =>
    {
        for (int i = 0i < 1000000; ++i)
        {
            for (int j = 0j < 1000000; ++j)
            {
                Math.Sqrt(j);
            }
        }
    });
    // 重たい処理終了

    test.Content = "End";
}






2.ウィンドウが固まる


重い処理を非同期処理で実装していない場合、ウィンドウが固ってしまいウィンドウを移動させることができないという問題が起こります。

重い処理をしているんだからウィンドウが動かせないぐらいいいだろうとか思う人もいるかもしれませんが、ユーザからしたら使い勝手が最悪です。

最小化ボタンとかがついていないアプリの場合、常に画面の前面にでてきてかなりうざいです。

オープンソースのアプリでもたまにそういったものがありますが、ユーザの使い勝手を考えましょう。


3.アプリがダウンする


先ほどウィンドウが固まるという話をしましたが、最悪アプリがダウンする可能性もあります。

実際に私の携わっていた仕事の一つでは5時間ほど処理時間がかかるのにその間に誤って画面をクリックするとアプリがダウンするというものもありました。

個人開発レベルでもこれは不便だと思うので非同期処理をいれて対策をしましょう。



まとめ


今回、重い処理を非同期処理でするべき代表的な理由3つを紹介しました。

他にも色々とふべんな点があるのですが、同期処理で実装するメリットは設計が楽で手抜きできるぐらいしかなくデメリットが大きいのでWPFアプリケーションを作る場合は、スレッドを意識しながら設計やコーディングをするようにしましょう。







3753817_s

WPFアプリケーションを作成していたらResizeModeをCanMinimizeにしているにも関わらず、アプリを付けたまま数時間放置していたらウィンドウが勝手に最大化するという問題が発生しました。

今回は同じ問題にはまった人のために対処法を紹介していきます。


【目次】
対処法
まとめ



ウィンドウが最大化する問題の対処法


根本原因をつかめるのが一番良かったのですが原因は分かりませんでした。

この問題が発生するPCと発生しないPCがあったりするのでWindowsの設定の問題なのかな…。

とりあえず対処法として画面が最大化したときだけ、自動的に画面を通常サイズに戻すというイベントを入れることにしました。

ウィンドウサイズが変更されたことはStateChangedを使って判断します。

サンプルコードは以下の通りです。

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        ResizeMode="CanResize"
        StateChanged="WindowStateChanged">
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel>
            <Label x:Name="Label1" Margin="10" Height="40" Width="200" HorizontalContentAlignment="Center"/>
            <Button Content="ボタン" Height="40" Width="80" Click="Button_Click"/>
        </StackPanel>
    </Grid>
</Window>



using System.Windows;



namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object senderRoutedEventArgs e)
        {
            Label1.Content = "Hello World!!";
        }

        private void WindowStateChanged(object senderobject e)
        {
            if (this.WindowState == WindowState.Maximized)
            {
                this.WindowState = WindowState.Normal;
            }
        }
    }
}


簡単にサンプルコードの説明をすると画面のサイズが変わるとStateChangedイベントが走り、WindowStateChangedメソッドをコールします。

WindowStateChangedは画面の状態が最大化なら通常サイズにするという処理をしているだけです、

今回サンプルなのでResizeModeはCanResizeにしているのですが、最大化をしたくない場合はResizeModeをCanMinimizeかNoResizeにしましょう。



まとめ


今回は勝手にウィンドウが最大化する問題の応急処置的な対処法を紹介しました。

誰か根本的な原因が分かる人がいればコメントで教えてほしいです…。

画面系のアプリは色々と奥が深くて難しいですね。



3753817_s

本記事ではVisual Studioを使ってWPFの開発環境を構築する方法を紹介していきます。



Visual Studioのダウンロード


最初にVisual Studioをインストールします。

すでにインストール済みの人は読み飛ばしてもらっても大丈夫です。

Visual Studioは以下のリンクからダウンロードできます。



コミュニティ版は学生、個人利用者、オープンソース貢献者は無償で使用できるみたいです。マイクロソフトは心が広いですね。

以下の画面の赤で囲まれている部分をクリックすることでダウンロードすることができます。

キャプチャ

ダウンロードが完了したらインストーラを起動してください。

インストーラを起動したら続行をクリックします。

キャプチャ

次に.NET デスクトップ環境にチェックを入れてインストールボタンをクリックしてください。

そうするとインストールが始まります。

キャプチャ

キャプチャ

インストールが完了すると一度PCの再起動を求められるので再起動してください。

キャプチャ

再起動がしたらデスクトップからメニューを開いてVの項目にあるVisual Studio2019を起動してください。

キャプチャ

起動するとマイクロソフトアカウントでのサインインが求められるのでサインインしてください。

アカウントがない場合は、アカウントを作成してください。

キャプチャ

サインインすると配色の設定が聞かれるので好みの色に設定してVisual Studioの開始をクリックします。

キャプチャ

以下の画面が起動したらVisual Studioが起動できたためインストールは完了です。

キャプチャ



WPFプロジェクトを作成する


Visual StudioがインストールできたろことでWPFのプロジェクトを作成していきます。

以下の画面から新しいプロジェクトの作成をクリックしてください。

キャプチャ

検索ボックスにWPFと入力して、以下の画像の赤枠で囲っているWPFアプリケーションを選択して次へをクリックしてください。

Visual Basic用などと間違えないように注意してください。

キャプチャ

プロジェクト名や場所は適当なものを入力して次へをクリックしてください。今回はデフォルトのままで進みます。

キャプチャ

ターゲットフレームワークもなんでもいいのですが今回は現時点で最新の5.0を使用します。

ターゲットフレームワークが選択できたら作成をクリックしてください。

キャプチャ

以下の画面が表示されたらWPFプロジェクトの作成は完了です。

キャプチャ





Hello Worldアプリを作成する


プロジェクトが作成できたら、ボタンを押したら画面にHello Worldと表示する単純なアプリを作成します。

ここではあくまでアプリを実行することを目的とするのでコードの意味などは説明しません。

MainWindow.xamlのコードを以下に示します。

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel>
            <Label x:Name="Label1" Margin="10" Height="40" Width="200" HorizontalContentAlignment="Center"/>
            <Button Content="ボタン" Height="40" Width="80" Click="Button_Click"/>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.csのコードを以下に示します。

using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object senderRoutedEventArgs e)
        {
            Label1.Content = "Hello World!!";
        }
    }
}

このコードを張り付けて、実行ボタンを押すとアプリが起動します。

キャプチャ

キャプチャ

ボタンをクリックすると画面中央にHello Worldと表示されます。

キャプチャ



まとめ


Visual StudioをインストールしてWPFでHello Worldアプリを作成するまで1時間ほどでできました。

関係ないですがいつの間にかホットリロード機能が付いたんですね!








↑このページのトップヘ