C#プログラミング

【C#】引数・戻り値のある非同期処理【Task】

引数と戻り値がある非同期処理記事のアイキャッチ画像 C#

本記事では、非同期処理に引数を渡し、戻り値を受け取る方法をサンプルプログラムとともに紹介します。この非同期処理を扱えればプログラミングの幅が大きく広がりますので是非参考にしてください。

スポンサーリンク

非同期処理Taskに関して

引数・戻り値のないよりシンプルな非同期処理の記事は以下です。初めて非同期処理を扱う方はまず以下記事を読んでからのほうが、本記事を理解しやすいと思います。

スポンサーリンク

引数・戻り値のある非同期処理Taskの実装方法

今回紹介する方法のプログラムを、そのまま日本語にすると以下の通り。

戻り値を受け取る変数 = await Task.Run<戻り値の型>(()=>非同期処理メソッド名(引数));

メソッドにはasync修飾子を記述してください。

この行を真似ればとりあえずプログラムは作れます。詳しく理解したい場合は、ジェネリック型、ラムダ式で調べてみてください。

スポンサーリンク

サンプルプログラム

MVVM形式で記載しています(他形式の方でもViewModelを参考にしていただけたらと思います)。
また本記事の本質と関係ない部分は省略しています(Model、コマンド機能の実装など)。

MVVMプロジェクトの作り方はこちらの記事をどうぞ。

作成したサンプルは、ボタンを押すと重い処理が非同期で実行されます。重い処理(メソッド)に引数を渡し、終了後には戻り値を受け取り、画面に表示(下画像右側の一番下)します。

スタートボタンを押す前の様子
ボタンを押す前の画面の様子
処理完了後の様子
非同期処理完了後の画面の様子

View

XAMLは以下の通り。

<Window x:Class="AsyncSample01.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="AsyncSample01" Height="250" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="20" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="20" />
            <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>

        <Button Grid.Row="1" Grid.Column="0" Margin="10" Content="START"
                Command="{Binding StartBtn1_Pushed}" />

        <TextBlock Grid.Row="0" Grid.Column="2" Text="◇Output"/>
        <ListView Grid.Row="1" Grid.Column="2" Grid.RowSpan="3" Margin="5" ItemsSource="{Binding rsltColl}"/>

        <TextBlock Grid.Row="4" Grid.Column="2" Text="{Binding rsltTxt}" />
    </Grid>
</Window>

コードビハインドは以下の通り。

namespace AsyncSample01.Views
{
    public partial class MainView : Window
    {
        public MainView()
        {
            InitializeComponent();

            MainViewModel vm = new MainViewModel();
            this.DataContext = vm;
        }
    }
}

ViewModel

非同期処理の記述はこちらにあります。

namespace AsyncSample01.ViewModels
{
    public class MainViewModel:INotifyPropertyChanged
    {

        //コマンド
        public ICommand StartBtn1_Pushed { get; set; }
        public ICommand StartBtn2_Pushed { get; set; }

        public MainViewModel()
        {
            //出力表示用のコレクション
            rsltColl = new ObservableCollection<string>();
            //コマンド
            StartBtn1_Pushed = new RelayCommand(Start1_cmd);

        }
        
        //ボタンクリックで呼び出されるイベント
        private async void Start1_cmd()
        {
            //出力要素のクリア
            rsltColl.Clear();

            rsltColl.Add(" - START - ");
            rsltTxt = await Task<string>.Run(() => HeavyMethod("-- Argument --"));
            rsltColl.Add(" - END - ");
        }

        //重い処理を含むメソッド(0-5をゆっくりカウント)
        private string HeavyMethod(string arg)
        {

            for (int i = 0; i <= 5; i++)
            {

                App.Current.Dispatcher.Invoke((Action)(() =>
                {
                    //引数とカウントを合わせた要素を追加
                    rsltColl.Add(arg + i.ToString());
                }));

                //重い処理想定で停止させる
                Thread.Sleep(1000);
            }

            //適当な文字列を返す
            return "== Return Text ==";
        }

        //出力表示用のコレクション
        private ObservableCollection<string> _rsltColl;
        public ObservableCollection<string> rsltColl
        {
            get { return _rsltColl; }
            set
            {
                _rsltColl = value;
                NotifyPropertyChanged("rsltColl");
            }
        }

        //処理結果を受ける文字列
        private string _rsltTxt;
        public string rsltTxt
        {
            get { return _rsltTxt; }
            set
            {
                _rsltTxt = value;
                NotifyPropertyChanged("rsltTxt");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }
}

以上、実装するだけなら割とシンプルかなと思います。

コメント

タイトルとURLをコピーしました