20200924のC#に関する記事は10件です。

(C#)次の平日を取得するLINQ

はじめに

C#で、次の平日を取得するコードをきれいに書けないかなと思ってLINQで試してみました。
もっといいコードがあればコメントいただけると嬉しいです。

環境

Windows 10
Visual Studio 2019

参考

こちらの記載にアイデアをもらいました。
https://tercel-tech.hatenablog.com/entry/2014/02/08/183432

コード

DateTimeの拡張メソッドとしています。

NextWeekday.cs
public static DateTime NextWeekday(this DateTime date,List<DateTime> holidayList = null) {
    // 100日後までの間で最も近い営業日を取得
    // 100は適当な大きな数値でOK
    DateTime next = Enumerable.Range(1, 100).Select(x => date.AddDays(x)).First(
        x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday && !(holidayList?.Contains(x) ?? false)
    );
    return next;
}

注意点

祝日リストはどこかから持ってくる AND DateTime.Todayなどで時刻部分は0の前提です。
単純に、「土曜日でない & 日曜日でない & 祝日リストに入ってない」日付を順に判定しています。

おわりに (今後の展開)

次は祝日リストですが、Google Calendar APIを調べてみたいと思います。
ここを参考にして試してみようと思っています。
https://blog.divakk.co.jp/entry/holidays

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】【DxLib】FPSが全然出ない!? そんな時はたった一行のコードを追加するだけで、一気に爆上がりするかも?

概要

今回はたった一行追加することで、FPSが上がるかも?というやり方を紹介します。
この記事は、DXライブラリの関数を用いて上の課題を解決していきます。
サンプルコードをコピペしたり、可能ならば必要な関数を覚えながら書き写しましょう。

やりたいこと

DxLib既存の関数を利用し、FPSをある程度上昇させたい。

whileより前部にある、DX.SetDrawScreen(DX.DX_SCREEN_BACK); は削除してしまって構わないです。

 // メインループ
 while (DX.ProcessMessage() != -1)
 {
     // 描画先を裏画面に設定
     SetDrawScreen(DX.DX_SCREEN_BACK);
     // 画面をクリア
     DX.ClearDrawScreen();

     //
     //処理();
     //

     // 裏画面の内容を表画面に反映する
     DX.ScreenFlip();
 }

説明

while処理内の先頭にSetDrawScreen(DX.DX_SCREEN_BACK);こちらの関数を呼び出しました。
ループするところにこんな関数を置いてしまって大丈夫なのか?と心配な方もいらっしゃるとは思いますが、画面・処理には何の支障をきたさないので安心してください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVVM Show View パターン2 Commandパラメータ

参考コード

ICommandインターフェイスを実装したコマンドを利用して、表示します。

MVVM_WindowCommands
https://github.com/mike-eason/MVVM_WindowCommands
のコードを見てみましょう。

View

コマンドを指定して、そのパラメータにウインドウ名を指定しています。

  <Button Content="Open Window"
                    Command="{Binding OpenWindowCommand}"
                    CommandParameter="{x:Type local:TestWindow}"/>

ViewModel

OpenWindowCommand

   public class MainWindowViewModel
    {
        public OpenWindowCommand OpenWindowCommand { get; private set; }
        public ShowDialogCommand ShowDialogCommand { get; private set; }

        public MainWindowViewModel()
        {
            OpenWindowCommand = new OpenWindowCommand();
            ShowDialogCommand = new ShowDialogCommand(PostOpenDialog, PreOpenDialog);
        }

Commandクラス(Modelに該当する部分?)

ここで、Showしています。
ViewとViewModel以外は、すべてModelと考えますから、この部分もModelという認識で良いと思いますが、どうでしょうか。

   public class OpenWindowCommand : ICommand
    {

        protected virtual void OpenWindow(Window wnd)
        {
            wnd.Show();
        }

分からない点

この処理の流れで、TestWindowを確定して表示を行っているのはどこでしょうか?
Viewでしょうか、ViewModelでしょうか、OpenWindowCommandでしょうか?
これは、x:Type local:TestWindow とTestWindowと名前を指定しているViewだと私は考えるのですが、違うのでしょうか?
ViewModelも、OpenWindowCommandも、引数を与えられて処理を行う部分ですから、TestWindowと確定しているわけではありません。
従って、TestWindowというViewを知っているのは、ViewのMainWindowだと私には思えます。そうすると、基本パターン1と、同じですね。基本パターン1はコードビハインドで、Viewから指定したViewを表示していますが、このパターンは、XAMLでコマンドを利用して、Viewから指定したViewを表示します。

TestWindowを指定するところを変更する場合

けれども、XAMLで

CommandParameter="{x:Type local:TestWindow}"

を指定せず、

  • MainWindowViewModelでTestWindowを指定する → VMが他のViewを知っている
  • OpenWindowCommandでTestWindowを指定する  → Mが他のViewを知っている

ことになると考えますが、この考え方で合っているでしょうか。

記事予定

  • パターン1 Viewのコードビハインド
  • パターン2 Commandパラメータ(この記事)
  • パターン3 Prism の Dialog Service
  • パターン4 引数を渡す
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVVM Show View パターン2 Commandパラメータ

参考コード

ICommandインターフェイスを実装したコマンドを利用して、表示します。

MVVM_WindowCommands
https://github.com/mike-eason/MVVM_WindowCommands
のコードを見てみましょう。

View

コマンドを指定して、そのパラメータにウインドウ名を指定しています。

  <Button Content="Open Window"
                    Command="{Binding OpenWindowCommand}"
                    CommandParameter="{x:Type local:TestWindow}"/>

ViewModel

OpenWindowCommand

   public class MainWindowViewModel
    {
        public OpenWindowCommand OpenWindowCommand { get; private set; }
        public ShowDialogCommand ShowDialogCommand { get; private set; }

        public MainWindowViewModel()
        {
            OpenWindowCommand = new OpenWindowCommand();
            ShowDialogCommand = new ShowDialogCommand(PostOpenDialog, PreOpenDialog);
        }

Commandクラス(Modelに該当する部分?)

ここで、Showしています。
ViewとViewModel以外は、すべてModelと考えますから、この部分もModelという認識で良いと思いますが、どうでしょうか。(VMのコードで、modelに相当するものではなく、単にView・ViewModelではないという意味で)

   public class OpenWindowCommand : ICommand
    {

        protected virtual void OpenWindow(Window wnd)
        {
            wnd.Show();
        }

分からない点

この処理の流れで、TestWindowを確定して表示を行っているのはどこでしょうか?
Viewでしょうか、ViewModelでしょうか、OpenWindowCommandでしょうか?
これは、x:Type local:TestWindow とTestWindowと名前を指定しているViewだと私は考えるのですが、違うのでしょうか?
ViewModelも、OpenWindowCommandも、引数を与えられて処理を行う部分ですから、TestWindowと確定しているわけではありません。
従って、TestWindowというViewを知っているのは、ViewのMainWindowだと私には思えます。そうすると、基本パターン1と、同じですね。基本パターン1はコードビハインドで、Viewから指定したViewを表示していますが、このパターンは、XAMLでコマンドを利用して、Viewから指定したViewを表示します。

TestWindowを指定するところを変更する場合

けれども、XAMLで

CommandParameter="{x:Type local:TestWindow}"

を指定せず、

  • MainWindowViewModelでTestWindowを指定する → VMが他のViewを知っている
  • OpenWindowCommandでTestWindowを指定する  → Mが他のViewを知っている

ことになると考えますが、この考え方で合っているでしょうか。

記事予定

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVVM Show View パターン 1 Viewのコードビハインド

Viewを表示するパターンを考える

MVVMを勉強しはじめた時に、いったいコードをどうかけばいいのかさっぱり分からなかったのことは、Viewを表示するコードをどこに書くのか?
今でもそれらが曖昧なので、明確にしておくためにこの記事を書きます。
ただし、調べると、より分からない点がさらに増えました。
フィードバックを頂けるとありがたいです。

Newする順序

V・VM・MをNewする順序も、パターンによって異なります。それにも留意します。

結合・参照?

MVVMでは、ModelはViewModelを知らないし、ViewModelはViewを知らない、ことが前提です。
この知らない、というのは、名前を知っているだけなのは知るうちに入るのか入らないのか。この点がよくわかりません。
例えば、SubView.xamlを新しく表示する場合、SubViewという確定している名前がコードに書かれているだけなら、それで知っていることになるのか?ということです。
これについては、パターン2の、Commandパラメータで考えます。

コード

https://github.com/mikihiro-t/MVVMPattern

開発環境

.NET Core 3.1 + ReactiveProperty で構築します。

パターン 1 Viewのコードビハインド

アプリを起動した時の最初のViewは、App.xamlのStartupUriで指定します。
それ以降のViewを、Viewのコードビハインドから表示します。

ファイルの構成

Class
Model MainManager
ViewModel MainViewModel
View MainView

Newする順序は、

  1. ViewからViewModelをNew
  2. NewされたViewModelから、ModelをNewします。

V → VM → M の順序です。

プロジェクトの構成

image.png

スタート時のウインドウ

App.xamlの、StartupUriに、MainView.xamlを指定しました。

<Application
    x:Class="ShowView1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ShowView1"
    StartupUri="View/MainView.xaml">

MainViewのコードビハインド

MainViewModelをNewしています。
DataContextに、vmをセットします。ここではなく、XAMLでVMを指定もできます。
ただし、ViewのコードビハインドでVMのメソッドを呼び出すことがあるなら、ここで指定しておくと便利だと思います。

  public partial class MainView : Window
    {
        MainViewModel vm = new MainViewModel();
        public MainView()
        {
            InitializeComponent();
            this.DataContext = vm;
        }

ViewModel

ModelをNewして保持します

    class MainViewModel : INotifyPropertyChanged, IDisposable
    {
        public MainManager Model { get; }

        public MainViewModel()
        {
            Model = new MainManager();

ボタンクリックで新しいViewを表示

ボタンをクリックして、別のViewを表示するには、

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var cls = new MainView();
            cls.Show();
        }

Viewのコードビハインドで良いはずです。
ここでは、2つめのMainViewを表示しています。

Viewと他のViewとの関係

ここでは、ボタンクリックで、MainViewをさらに表示していますが、他のViewを表示するのも同じです。

SubViewがあるとすれば、

  • MainViewのボタンクリック
  • SubViewを表示

になります。
これだと、MainViewは、SubViewを知っていることになります。SubViewという名前を知っているし、参照もしています。MVVMとして、それで良いのかどうかが分かりません。

View1が、View2を、表示する処理(閉じる処理も?)を、View1で行って良いとすると、また、例えば、View2のDialogResultを、View1で受け取り、ViewModel, ViewModel経由でModelで処理をする程度のこともOKかもしれません。

Viewのコードビハインドの是非

Viewには、できるだけコードを書かないでおこうという考え方もあるのですが、私は次の条件の時は、Viewにコードを書くと良いと考えます。

  • Viewに関わる事
  • Viewのコードで処理した方が、ViewModelやModelで処理するより容易

XAMLに書くのも、Viewにコードビハインドで書くのも同じViewでの処理です。単に、言語がXAMLなのかC#なのか程度の違いです。
https://stackoverflow.com/a/37294259/9924249

XAMLだけで処理をしようとして、複雑なコードになるのは本末転倒な気がします。また、UIのテストが行いやすくなるからXAMLだけで処理をしようとするのも、同様に本末転倒に思います。

同様の例

Handle it in the view
https://stackoverflow.com/a/5829704/9924249

private void AddCustomerView_Click(object sender, RoutedEventArgs e)
{
    AddCustomerView view = new AddCustomerView(data);
    view.Show();
}

となっています。ここでは、ViewをNewする時に、引数としてdataを渡していますが、このdataはモデルのデータであるはずです。それを、Viewから渡すことは、MVVMらしいでしょうか? これも分からない点です。

疑問点まとめ

  • Viewが他のViewを知っているのはMVVMとしてそれでよいのか?
  • ViewからViewを表示する場合、引数(Modelのデータ)をどうやって渡すのか?

単純な処理なようで、疑問も増えました。このパターンを基本として、他のパターンと比べていきましょう。

記事予定

  • パターン1 Viewのコードビハインド(この記事)
  • パターン2 Commandパラメータ
  • パターン3 Prism の Dialog Service(予定)
  • パターン4 引数を渡す(予定)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVVM Show View パターン1 Viewのコードビハインド

Viewを表示するパターンを考える

MVVMを勉強しはじめた時に、いったいコードをどうかけばいいのかさっぱり分からなかったのことは、Viewを表示するコードをどこに書くのか?
今でもそれらが曖昧なので、明確にしておくためにこの記事を書きます。
ただし、調べると、より分からない点がさらに増えました。
フィードバックを頂けるとありがたいです。

Newする順序

V・VM・MをNewする順序も、パターンによって異なります。それにも留意します。

結合・参照?

MVVMでは、ModelはViewModelを知らないし、ViewModelはViewを知らない、ことが前提です。
この知らない、というのは、名前を知っているだけなのは知るうちに入るのか入らないのか。この点がよくわかりません。
例えば、SubView.xamlを新しく表示する場合、SubViewという確定している名前がコードに書かれているだけなら、それで知っていることになるのか?ということです。
これについては、パターン2の、Commandパラメータで考えます。

コード

https://github.com/mikihiro-t/MVVMPattern

開発環境

.NET Core 3.1 + ReactiveProperty で構築します。

パターン 1 Viewのコードビハインド

アプリを起動した時の最初のViewは、App.xamlのStartupUriで指定します。
それ以降のViewを、Viewのコードビハインドから表示します。

ファイルの構成

Class
Model MainManager
ViewModel MainViewModel
View MainView

Newする順序は、

  1. ViewからViewModelをNew
  2. NewされたViewModelから、ModelをNewします。

V → VM → M の順序です。

プロジェクトの構成

image.png

スタート時のウインドウ

App.xamlの、StartupUriに、MainView.xamlを指定しました。

<Application
    x:Class="ShowView1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ShowView1"
    StartupUri="View/MainView.xaml">

MainViewのコードビハインド

MainViewModelをNewしています。
DataContextに、vmをセットします。ここではなく、XAMLでVMを指定もできます。
ただし、ViewのコードビハインドでVMのメソッドを呼び出すことがあるなら、ここで指定しておくと便利だと思います。

  public partial class MainView : Window
    {
        MainViewModel vm = new MainViewModel();
        public MainView()
        {
            InitializeComponent();
            this.DataContext = vm;
        }

ViewModel

ModelをNewして保持します

    class MainViewModel : INotifyPropertyChanged, IDisposable
    {
        public MainManager Model { get; }

        public MainViewModel()
        {
            Model = new MainManager();

ボタンクリックで新しいViewを表示

ボタンをクリックして、別のViewを表示するには、

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var cls = new MainView();
            cls.Show();
        }

Viewのコードビハインドで良いはずです。
ここでは、2つめのMainViewを表示しています。

Viewと他のViewとの関係

ここでは、ボタンクリックで、MainViewをさらに表示していますが、他のViewを表示するのも同じです。

SubViewがあるとすれば、

  • MainViewのボタンクリック
  • SubViewを表示

になります。
これだと、MainViewは、SubViewを知っていることになります。SubViewという名前を知っているし、参照もしています。MVVMとして、それで良いのかどうかが分かりません。

View1が、View2を、表示する処理(閉じる処理も?)を、View1で行って良いとすると、また、例えば、View2のDialogResultを、View1で受け取り、ViewModel, ViewModel経由でModelで処理をする程度のこともOKかもしれません。

Viewのコードビハインドの是非

Viewには、できるだけコードを書かないでおこうという考え方もあるのですが、私は次の条件の時は、Viewにコードを書くと良いと考えます。

  • Viewに関わる事
  • Viewのコードで処理した方が、ViewModelやModelで処理するより容易

XAMLに書くのも、Viewにコードビハインドで書くのも同じViewでの処理です。単に、言語がXAMLなのかC#なのか程度の違いです。
https://stackoverflow.com/a/37294259/9924249

XAMLだけで処理をしようとして、複雑なコードになるのは本末転倒な気がします。また、UIのテストが行いやすくなるからXAMLだけで処理をしようとするのも、同様に本末転倒に思います。

同様の例

Handle it in the view
https://stackoverflow.com/a/5829704/9924249

private void AddCustomerView_Click(object sender, RoutedEventArgs e)
{
    AddCustomerView view = new AddCustomerView(data);
    view.Show();
}

となっています。ここでは、ViewをNewする時に、引数としてdataを渡していますが、このdataはモデルのデータであるはずです。それを、Viewから渡すことは、MVVMらしいでしょうか? これも分からない点です。

疑問点まとめ

  • Viewが他のViewを知っているのはMVVMとしてそれでよいのか?
  • ViewからViewを表示する場合、引数(Modelのデータ)をどうやって渡すのか?

単純な処理なようで、疑問も増えました。このパターンを基本として、他のパターンと比べていきましょう。

記事予定

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# Conditional属性の罠

問題の概要

defineを定義し、Conditionalを使用したのに何故か関数が呼ばれないぞ???
といった事件に出会しました。

こんな感じ

#define Debug_AAA
public class AAA
{
    public AAA()
    {
        new BBB().Method_DebugAAA();
        new BBB().Method_DebugBBB();
    }
}
#define Debug_BBB

using System.Diagnostics;

public class BBB
{
    [Conditional ("Debug_AAA")]
    public void Method_DebugAAA()
    {
        UnityEngine.Debug.Log("AAAから呼び出したなら、ログが出るよ");
    }

    [Conditional ("Debug_BBB")]
    public void Method_DebugBBB()
    {
        UnityEngine.Debug.Log("AAAから呼び出した時は、ログが出ないよ");
    }
}

(Unityで作業してたので、ログ出力がUnity仕様なのは堪忍でござる)

どゆこと?

どうやら、Conditional属性はスクリプト内のdefineではなく、呼び出し元のdefineを参照してるらしい。
(リファレンス読んでない人並みの感想)
そもそも、各々のスクリプトでdefineを設定してるのが良くないのかもしれませんね ^^;

最後に

defineを外(例えばUnityのScriptingDefineSymbols等)で定義してて
下記のように使いたい時に困っちゃう...気が...

#if Debug_AAA || Debug_BBB
#define ORIGINAL_DEBUG
#endif

[Conditional ("ORIGINAL_DEBUG")]
public void OriginalDebugMethod(){}

とりあえず私のプロジェクトではdefineを整理することにしてみます。
場合によっては素直に#if使うとかですかね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure の静的サイトをホストする Azure Static Web Apps が Blazor と C# の Functions サポートしたらしいので試してみた

まだプレビューのサービスですが、期待大の Azure Static Web Apps で Blazor と C# の関数がサポートされました。以下のブログでアナウンスされてます。

Azure Static Web Apps with .NET and Blazor

Microsoft MVP の三宅さんのツイートのトップにも、このサービス関連のスライドがピン止めされてますね!

Azure Static Web Apps の更新情報を確認してみると Python もサポートされていたりして着々と開発が進んでるみたいです。

Blazor + C# の Functions の試し方

最初に紹介したブログに書いてあるのですが、若干気を付ける点があったので書いておこうと思います。
ブログにある GitHub のリポジトリを自分のアカウントにコピーして始めるのですが、これをクローンして Api プロジェクトと Client プロジェクトをローカルで実行して Client の Fetch data のページを開くと CORS のエラーが出ます。

image.png

これは、デフォルトでローカル開発用の設定ファイルの local.settings.json.gitignore に入ってるのでリポジトリに含まれていないためです。なので以下の内容の local.settings.json を Api プロジェクトに追加することでエラー無しでローカルで実行できます。

local.settings.json
{
  "Values": {
  },
  "Host": {
    "CORS":  "*"
  }
}

これを追加して実行すると以下のようにローカルで動くようになります。

image.png

Client プロジェクトの Program.cs を見てみると builder.Configuration["BaseAddress"] ?? builder.HostEnvironment.BaseAddress という感じで設定に BaseAddress という設定があったら HttpClientBaseAddress に設定しています。設定にない場合はホストの BaseAddress を使うようになっています。

Program.cs
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorApp.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");

            var baseAddress = builder.Configuration["BaseAddress"] ?? builder.HostEnvironment.BaseAddress;
            builder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(baseAddress) });

            await builder.Build().RunAsync();
        }
    }
}

Blazor WebAssembly の開発中のみ有効な設定は wwwroot/appsettings.Development.json に書いてあって、ここに BaseAddresshttp://localhost:7071/ であると書いてあります。

appsettings.Development.json
{
  "BaseAddress": "http://localhost:7071/"
}

これでローカルの時だけローカルで実行している Azure Functions の方を見に行くようになっています。Azure Static Web Apps にデプロイしたときは、関数は同じホストにいるので同じホストの /api/関数名 を見に行くようになっています。なるほどね。

デプロイして実行

デプロイから実行するのは本当にトラブルがないです。routes.json もリポジトリに入ってるし。フレームワークの中の選択肢に Blazor も入ってるし。

image.png

既存のプロジェクトがあって、それに合わせるとなるとちょっとカスタム頑張らないとですが、そうじゃなければ Static Web Apps が想定しているものに合わせるのがいいですね。

デプロイが完了すると紐づけた GitHub のリポジトリに自動で GitHub Actions が構成されて動きます。

image.png

動き終わるとちゃんと表示されました。

image.png

PullRequest の時に確認用の環境をたててくれたりとかは試してませんが、生成された GitHub Actions を見る限り対応してくれてそうでした。

まとめ

ということで、ローカル実行を試してみようと思ったら local.settings.json を作っておかないと CORS のエラーになってしまいますが、そこさえ気を付けていれば割と簡単にローカル実行から Static Web Apps へのデプロイまでを体験するのは、そんなに難しくないと感じました。

今のところ一番 GA が待ち遠しいサービスなので期待大ですね!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#のActionは途中でExceptionを起こすと中断される

思てたんとちがう!

C#Actionをコールバックのリスナとして利用していたところ「思てたんとちがう!」という挙動があったので、改めて検証しました。
Unity.NET 4.xで実行していますが、C#ならどのプラットフォームでも同じことが起こると思います。

テストコード

テストコード
// コールバック用のリスナー
public event Action OnSomething;

private void Start()
{
    // コールバックをそれぞれ登録
    OnSomething += OnSomething1;
    OnSomething += OnSomething2;
    OnSomething += OnSomething3;

    // イベントを実行
    OnSomething?.Invoke();
}

private void OnSomething1()
{
    Debug.Log("1");
}

private void OnSomething2()
{
    throw new NotImplementedException();
}

private void OnSomething3()
{
    Debug.Log("3");
}

このコードを実行するとこうなります。

ログ
1
NotImplementedException: The method or operation is not implemented.

本来ならばOnSomething1〜3は独立のため、2でExceptionが起きても3が実行されてほしいところですが、出力されていません。

こんな感じでtry-catchしてあげると3も実行されます。

try-catch
private void OnSomething2()
{
    try
    {
        throw new NotImplementedException();
    }
    catch (Exception e)
    {
        Debug.LogException(e);
    }
}
ログ
1
NotImplementedException: The method or operation is not implemented.
3

何が怖いか

「コールバック公開しておくから、誰でも好きにイベント登録しといてくれよな!」というのがわりと一般的な使い方と思いますが、この挙動だと「他のところで登録した誰かがthrowしたら自分のところにイベントが来なくなる(しかもそれを知ることすらできない)」というなかなか恐ろしいことになります。

C#Actionは他にもラムダ式でイベント登録すると解除できなかったり、いろいろ「コワ〜」な挙動が多いです。それすらもなかった昔よりはマシになっているだろうと言われればそうなのですが……。

なにはともあれ、良い子はイベント購読側で、イベントを購読しているという状態をインスタンスとして保持・破棄できるReactiveExtensionとかUniRx使おうね!1 という話でした。

おしまい。


  1. とはいえRxもまだ人類には早すぎる代物感がある。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

inputFieldのTMP版をスクリプトで使う方法。

最終的にはこんな感じになる。
ezgif.com-video-to-gif.gif

テキストメッシュプロで日本語が使える設定などは各自で済ませておいてください。
それについては参考になるようなサイトを貼っておきます↓
TextMeshProで日本語フォントを使用する【Unity】

では早速始めにCreate→UI→InputField - TextMeshProを選択。
その後空のゲームオブジェクトを作る。

“shot” 2020-09-24 0.01.34.png

次に新しくスクリプトを作る。
スクリプトの名前はなんでもよし。
スクリプトを作成したら

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

のusing〜と書いてあるところに

using TMPro;

を追加する。

その後「TMP_InputField」型の変数を宣言。↓のように書く。
ここでは変数の名前を「_inputField」としている。

public class Textscript : MonoBehaviour
{

    TMP_InputField _inputField;

    void Start()
    {

その後Startの中でInputField (TMP)のゲームオブジェクトを探し、そこに「TMP_InputField」をGetComponentする。

    void Start()
    {
        _inputField = GameObject.Find("InputField (TMP)").GetComponent<TMP_InputField>();


    }

その後「public」で「InputName」という関数を作ります。
↓関数の中身も含めこんな感じです。

    public void InputName()
    {
        string name = _inputField.text;
        Debug.Log(name);

        _inputField.text = "";
    }

中身の説明としてstring型のnameという変数に、先ほど作った「TMP_InputField」型の「_inputField」という変数の中のtextを入れる。
そしてDebug.Log(name)でコンソールに出力。
という感じ。
ここまでのスクリプトの全体を貼っておきます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class Textscript : MonoBehaviour
{
    TMP_InputField _inputField;

    void Start()
    {
        _inputField = GameObject.Find("InputField (TMP)").GetComponent<TMP_InputField>();
    }

    void Update()
    {

    }

    public void InputName()
    {
        string name = _inputField.text;
        Debug.Log(name);
    }

}

スクリプトはここまでで、作り終わったら先ほど作った空のゲームオブジェクトにこのスクリプトを貼っつける。

そしたら「InputField (TMP)」のインスペクタービューの「On End Edit(String)」の「+」を押し、「None」の部分にスクリプトがついている空のゲームオブジェクトをドラッグ。
右に色々選択できるところがあるので、そこで先ほど作ったスクリプトの名前を探し、その中に先ほど作った関数「InputName」があるのでそれを選択。
そうするとこうなる↓。

“shot” 2020-09-24 0.05.19.png

以上。
一番上のGIF画像みたいに入力した文字がコンソールに出力されるはず。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む