20200219のC#に関する記事は6件です。

cscの作法 その40

概要

cscの作法、調べてみた。
スクリーンセーバー作ってみた。

サンプルコード

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing.Drawing2D;

public class Form1: Form {
    public Form1() {
        this.FormBorderStyle = FormBorderStyle.None;
        this.WindowState = FormWindowState.Maximized;
        this.KeyDown += new KeyEventHandler(this.MyKeyDown);
        this.MouseDown += new MouseEventHandler(this.MyMouseDown);
        this.ClientSize = new Size(640, 480);
        Opacity = 0.3;
        Timer timer = new Timer();
        timer.Interval = 1000; 
        timer.Tick += new EventHandler(timerTick);
        timer.Start();
    }
    private void MyMouseDown(object sender, MouseEventArgs ev) {
        Application.Exit();
    }
    private void MyKeyDown(object sender, KeyEventArgs ev) {
        Application.Exit();
    }
    protected override void OnPaint(PaintEventArgs e) {
        Graphics g = e.Graphics;
        g.TranslateTransform(ClientSize.Width / 2, ClientSize.Height / 2, MatrixOrder.Append);
        Pen BPen = new Pen(Color.Blue, 5);
        Pen GPen = new Pen(Color.Green, 5);
        Pen RPen = new Pen(Color.Red, 3);
        Point center = new Point(0, 0);
        DateTime time = DateTime.Now;
        double secAng = 2.0 * Math.PI * time.Second / 60.0;
        double minAng = 2.0 * Math.PI * (time.Minute + time.Second / 60.0) / 60.0;
        double hourAng = 2.0 * Math.PI * (time.Hour + time.Minute / 60.0) / 12.0;
        int r = Math.Min(ClientSize.Width, ClientSize.Height) / 2;
        int secHandLength = (int) (0.9 * r);
        int minHandLength = (int) (0.9 * r);
        int hourHandLength = (int) (0.7 * r);
        Point secHand = new Point((int) (secHandLength * Math.Sin(secAng)), (int) (-secHandLength * Math.Cos(secAng)));
        Point minHand = new Point((int) (minHandLength * Math.Sin(minAng)), (int) (-minHandLength * Math.Cos(minAng)));
        Point hourHand = new Point((int) (hourHandLength * Math.Sin(hourAng)), (int) (-hourHandLength * Math.Cos(hourAng)));
        g.DrawLine(RPen, center, secHand);
        g.DrawLine(GPen, center, minHand);
        g.DrawLine(BPen, center, hourHand);
    }
    void timerTick(object sender, EventArgs e) {
        this.Invalidate();
    }
    [STAThread]
    static void Main(string[] args) {
        if (args.Length == 0 || string.Compare(args[0], "/s", true) == 0)
        {
            Form form = new Form1();
            form.ShowDialog();
        }
        Application.Exit();
    }
}



以上。

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

C#でBuilderパターン

コンストラクタの引数が多い

Studentクラスは名前と誕生日を必須の情報として持っていて、オプションでニックネームがついている。
こんなクラスを使いたいと思いました。

var taro = new Student("太郎", new DateTime(1990, 1, 1));
var sachiko = new Student("幸子", new DateTime(1990, 1, 1), "さっちゃん")

必須2個と任意1個の引数だからまだいいけど、増えてくるととても大変になります。
そして任意のパラメータ分のオーバーロードを書きたくない。

メソッドチェーンで書きたい

コンストラクタを呼ぶときにパラメータを順次設定するメソッドを呼び出したいですね。

var taro = Student.Builder.Instance
                .SetName("Taro")
                .SetBirth(new DateTime(1995, 4, 18))
                .SetNickname("タロ")
                .Build();

var sachiko = Student.Builder.Instance
                .SetName("幸子")
                .Build();  // 誕生日をセットしていないのでコンパイルエラーにしたい

SetNameとSetBirthは必須だがSetNicknameは呼ばなくてもbuildしたい。
これは以下のコードで実現できます。

public class Student
    {
        public string Name { get; }
        public DateTime Birth { get; }
        public string Nickname { get; }

        private Student(Builder builder)
        {
            Name = builder.Name;
            Birth = builder.Birth;
            Nickname = builder.Nickname;
        }

        public interface IHasName
        {
            IHasBirth SetName(string name);
        }

        public interface IHasBirth
        {
            Builder SetBirth(DateTime birth);
        }

        public sealed class Builder : IHasName, IHasBirth
        {
            internal string Name { get; private set; }
            internal DateTime Birth { get; private set; }
            internal string Nickname { get; private set; } = "";

            public static IHasName Instance
            {
                get { return new Builder(); }
            }

            private Builder() { }

            public IHasBirth SetName(string name)
            {
                Name = name;
                return this;
            }

            public Builder SetBirth(DateTime birth)
            {
                Birth = birth;
                return this;
            }

            public Builder SetNickname(string nickname)
            {
                Nickname = nickname;
                return this;
            }

            public Student Build()
            {
                return new Student(this);
            }
        }
    }

StudentとBuilderクラスのコンストラクタはprivateにしてあるので、Instanceを介さないとインスタンス化できません。
InstanceからはIHasNameが返るのでSetName以外は呼べません。
そしてSetNameからはSetBirthしか呼べません。
SetBirthからはSetNicknameもできるし設定せずにインスタンス化もできます。

そしてStudentインスタンスはreadonlyなフィールドだけを持つので、どこかで変更されることもありません。必要に応じてメソッドを追加していきましょう。

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

C#でBuilderパターン(effective java)

コンストラクタの引数が多い

Studentクラスは名前と誕生日を必須の情報として持っていて、オプションでニックネームがついている。
こんなクラスを使いたいと思いました。

var taro = new Student("太郎", new DateTime(1990, 1, 1));
var sachiko = new Student("幸子", new DateTime(1990, 1, 1), "さっちゃん");

必須2個と任意1個の引数だからまだいいけど、増えてくるととても大変になります。
そして任意のパラメータ分のオーバーロードを書きたくない。

メソッドチェーンで書きたい

コンストラクタを呼ぶときにパラメータを順次設定するメソッドを呼び出したいですね。

var taro = Student.Builder.Instance
                .SetName("Taro")
                .SetBirth(new DateTime(1995, 4, 18))
                .SetNickname("タロ")
                .Build();

var sachiko = Student.Builder.Instance
                .SetName("幸子")
                .Build();  // 誕生日をセットしていないのでコンパイルエラーにしたい

SetNameとSetBirthは必須だがSetNicknameは呼ばなくてもbuildしたい。
これは以下のコードで実現できます。

public class Student
    {
        public string Name { get; }
        public DateTime Birth { get; }
        public string Nickname { get; }

        private Student(Builder builder)
        {
            Name = builder.Name;
            Birth = builder.Birth;
            Nickname = builder.Nickname;
        }

        public interface IHasName
        {
            IHasBirth SetName(string name);
        }

        public interface IHasBirth
        {
            Builder SetBirth(DateTime birth);
        }

        public sealed class Builder : IHasName, IHasBirth
        {
            internal string Name { get; private set; }
            internal DateTime Birth { get; private set; }
            internal string Nickname { get; private set; } = "";

            public static IHasName Instance
            {
                get { return new Builder(); }
            }

            private Builder() { }

            public IHasBirth SetName(string name)
            {
                Name = name;
                return this;
            }

            public Builder SetBirth(DateTime birth)
            {
                Birth = birth;
                return this;
            }

            public Builder SetNickname(string nickname)
            {
                Nickname = nickname;
                return this;
            }

            public Student Build()
            {
                return new Student(this);
            }
        }
    }

StudentとBuilderクラスのコンストラクタはprivateにしてあるので、Instanceを介さないとインスタンス化できません。
InstanceからはIHasNameが返るのでSetName以外は呼べません。
そしてSetNameからはSetBirthしか呼べません。
SetBirthからはSetNicknameもできるし設定せずにインスタンス化もできます。

そしてStudentインスタンスはreadonlyなフィールドだけを持つので、どこかで変更されることもありません。必要に応じてメソッドを追加していきましょう。

参考

Builderパターン(Effective Java)

なんぞこれ。コンストラクタパラメータが異常に大杉る・・・。バカなの?死ぬの?そういう場合はBuilderパターンを検討してみよう。

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

【質問】C#について

初心者過ぎる私ですが、教えていただきたいことがございます。
超初歩的な質問なのですが、コードを描いたのですがエラーの解決が出来ません。
どうかご教示頂けませんでしょうか?
よろしくお願い致します。
//rows => 行、cells => 列
dgv.Rows[rowNo].Cells[1].Value = reader[0];
dgv.Rows[rowNo].Cells[2].Value = reader[1];
dgv.Rows[rowNo].Cells[3].Value = reader[2];
dgv.Rows[rowNo].Cells[5].Value = reader[3];
dgv.Rows[rowNo].Cells[6].Value = reader[4];
dgv.Rows[rowNo].Cells[7].Value = reader[5];

                DateTime dt1 = dgv.Rows[0].Cells[3].Value.();
                DateTime dt2 = DateTime.Now;
                TimeSpan ts2 = dt1 - dt2;
                dgv.Rows[rowNo].Cells[4].Value = ts2;

DateTime dt1 = dgv.Rows[0].Cells[3].Value.();の部分ですが、
上記に記載のdgvの3列めの値を使いたいのですが上手く思いつきません。
お願い致します。

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

UpdateではなくCoroutineで処理を行ってみる

初めに

この記事を書いた理由は前回の記事で頂いたコメントを参考にちょっと処理を変えてみたからです。

前回の記事で頂いたコメントの内容は「Update関数内でfadeの判定をしてしまうとfadeを望まないタイミングでもずっと判定してしまうので無駄が発生してしまうから別の処理に変えた方がいいよ!」という内容でした。

改善してみた

Updete内で行っていた処理を全てコルーチンに置き換えてみました
以下プログラム

SceneFadeManager.cs
public class SceneFadeManager : MonoBehaviour
{
    //透明度が変わるスピード
    float fadeSpeed = 0.75f;
    //画面をフェードさせるための画像をパブリックで取得
    public Image fadeImage;
    //画像のRGBA値設定用
    float red, green, blue, alfa;
    //シーン遷移のための型
    string afterScene;
    //フェードイン用のコルーチン
    IEnumerator fadeInCoroutine;
    //フェードアウト用のコルーチン
    IEnumerator fadeOutCoroutine;
    // Start is called before the first frame update
    void Start()
    {
        fadeInCoroutine = FadeIn();
        fadeOutCoroutine = FadeOut();
        DontDestroyOnLoad(this);
        SetRGBA(0, 0, 0, 1);
        StartCoroutine(fadeInCoroutine);
        //シーン遷移が完了した際にフェードインを開始するように設定
        SceneManager.sceneLoaded += fadeInStart;
    }
    //シーン遷移が完了した際にフェードインを開始するように設定
    void fadeInStart(Scene scene,LoadSceneMode mode)
    {
        fadeInCoroutine = FadeIn();
        StartCoroutine(fadeInCoroutine);
    }
    /// <summary>
    /// フェードアウト開始時の画像のRGBA値と次のシーン名を指定
    /// </summary>
    /// <param name="red">画像の赤成分</param>
    /// <param name="green">画像の緑成分</param>
    /// <param name="blue">画像の青成分</param>
    /// <param name="alfa">画像の透明度</param>
    /// <param name="nextScene">遷移先のシーン名</param>
    public void fadeOutStart(int red,int green,int blue,int alfa,string nextScene)
    {
        SetRGBA(red, green, blue, alfa);
        SetColor();
        afterScene = nextScene;
        fadeOutCoroutine = FadeOut();
        StartCoroutine(fadeOutCoroutine);
    }
    IEnumerator FadeIn()
    {
        for (int i = 0; i < 360; i++)
        {
            //不透明度を徐々に下げる
            alfa = Mathf.MoveTowards(alfa, 0f, fadeSpeed * Time.deltaTime);
            //変更した透明度を画像に反映させる関数を呼ぶ
            SetColor();
            yield return null;
            if (alfa <= 0)
                StopCoroutine(fadeInCoroutine);
        }
    }
    IEnumerator FadeOut()
    {
        for (int i = 0; i < 360; i++)
        {
            //不透明度を徐々に上げる
            alfa = Mathf.MoveTowards(alfa, 1f, fadeSpeed * Time.deltaTime);
            //変更した透明度を画像に反映させる関数を呼ぶ
            SetColor();
            yield return null;
            if (alfa >= 1)
            {
                SceneManager.LoadScene(afterScene);
                StopCoroutine(fadeOutCoroutine);
            }
        }
    }
    //画像に色を代入する関数
    void SetColor()
    {
        fadeImage.color = new Color(red, green, blue, alfa);
    }
    //色の値を設定するための関数
    public void SetRGBA(int r, int g, int b, int a)
    {
        red = r;
        green = g;
        blue = b;
        alfa = a;
    }
}

感想

実際に処理を変えてみるとシーン内に余り物を置いていないので劇的に変わったとまではいきませんが、
シーンを切り替えたときにFPS値の減少が少なくなっていました。
ほぼ何も置いていないシーンで変化が起きたということは、もっと大きなゲームになると、とてつもない影響が出るのではないかと思いました。
これからゲームを作るときには処理をすぐにプログラムしてこれでいいやとするのではなく、もっといい処理方法がないか考えてプログラムしていこうと思います。

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

Azureみたいなウィザードっぽい入力フォームを作りたい Phase2 とまどいの確認画面実装編

ローカルでも動くように、ちょっとファイルを書き換えた。

以下のフォルダ構成にすることで、ローカルでも動くようにした。

index.html(本記事のソースをコピペしただけのHTMLファイル)
AdminLTE-3.0.2(フォルダ)
css
img
js
plugins

css, img, jsはAdminLTE3をダウンロードしたときにdistフォルダ直下に入ってるもの。
pluginsはAdminLTE3をダウンロードしたときにindex.htmlとかと同じフォルダに入ってるやつ。

結論から言うと、確認画面以外はそれっぽく作成できた。

ソースは以下。(クリックするとソースが表示されます)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="x-ua-compatible" content="ie=edge">

    <title>テストページ</title>

    <!-- Font Awesome Icons -->
    <link rel="stylesheet" href="AdminLTE-3.0.2/plugins/fontawesome-free/css/all.min.css">
    <!-- Theme style -->
    <link rel="stylesheet" href="AdminLTE-3.0.2/css/adminlte.min.css">
    <!-- Google Font: Source Sans Pro -->
    <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
</head>

<body>
<div class="split-input-form container-fluid">
    <div class="Title">分割入力フォーム</div>

    <div class="docking">
        <div class="docking-body p-3">
            <ul class="nav nav-tabs">
                <li class="nav-item">
                    <a href="#tab1-content" class="nav-link" data-toggle="tab">基本</a>
                </li>
                <li class="nav-item">
                    <a href="#tab2-content" class="nav-link" data-toggle="tab">住所</a>
                </li>
                <li class="nav-item">
                    <a href="#tab3-content" class="nav-link" data-toggle="tab">連絡先</a>
                </li>
                <li class="nav-item">
                    <a href="#tab4-content" class="nav-link" data-toggle="tab">確認</a>
                </li>
            </ul>
            <div class="tab-content">
                <div id="tab1-content" class="tab-pane active">
                    <div>
                        <span>基本の情報を入力します。</span>
                    </div>
                    <br />
                    <div class="font-weight-bold" style="margin: 10px 0px;">基本情報</div>
                    <div>
                        <span>あなたの名前と年齢を入力します。</span>
                    </div>
                    <br />
                    <div class="row form-group">
                        <label class="col-xl-1 d-flex align-items-center">
                            名前
                        </label>
                        <input type="text" class="col-xl-11 form-control" onchange="InputNameFunc(this.value)" id="InputName" placeholder="名前を入力" />
                    </div>
                    <br />
                    <div class="row form-group">
                        <label class="col-xl-1 d-flex align-items-center">
                            年齢
                        </label>
                        <input type="text" class="col-xl-11 form-control" id="InputAge" placeholder="年齢を入力" />
                    </div>
                </div>
                <div id="tab2-content" class="tab-pane">
                    <div>
                        <span>あなたの住所を入力します。</span>
                    </div>
                    <br />
                    <!-- general form elements -->
                    <div class="row form-group">
                        <label for="selectPrefectureLabel" class="col-xl-1 d-flex align-items-center">
                            都道府県
                        </label>
                        <select class="form-control" id="selectPrefecture">
                            <option>北海道</option>
                            <option>本州</option>
                            <option>四国</option>
                            <option>九州</option>
                        </select>
                    </div>
                    <br />
                    <div class="form-group">
                        <label for="selectAreaLabel" class="col-xl-1 d-flex align-items-center">
                            地域
                        </label>
                        <div class="custom-control custom-radio">
                            <input class="custom-control-input" type="radio" id="AreaRadioWest" name="AreaRadio" checked="" value="どちらかというと西">
                            <label for="AreaRadioWest" class="custom-control-label">
                                どちらかというと西
                            </label>
                        </div>
                        <div class="custom-control custom-radio">
                            <input class="custom-control-input" type="radio" id="AreaRadioEast" name="AreaRadio" value="どちらかというと東">
                            <label for="AreaRadioEast" class="custom-control-label">
                                どちらかというと東
                            </label>
                        </div>
                    </div>
                </div>
                <div id="tab3-content" class="tab-pane">
                    <div>
                        <span>希望する連絡手段を選んでください。(複数選択可能)</span>
                    </div>
                    <br />
                    <div class="form-group">
                        <div class="custom-control custom-checkbox">
                            <input class="custom-control-input" type="checkbox" id="customboxMobile" value="携帯電話" />
                            <label for="customboxMobile" class="custom-control-label">
                                携帯電話
                            </label>
                        </div>
                        <div class="custom-control custom-checkbox">
                            <input class="custom-control-input" type="checkbox" id="customboxPhone" value="固定電話" />
                            <label for="customboxPhone" class="custom-control-label">
                                固定電話
                            </label>
                        </div>
                        <div class="custom-control custom-checkbox">
                            <input class="custom-control-input" type="checkbox" id="customboxFax" value="FAX" />
                            <label for="customboxFax" class="custom-control-label">
                                FAX
                            </label>
                        </div>
                    </div>
                </div>
                <div id="tab4-content" class="tab-pane">
                    <div>
                        <span>入力した内容を確認します。以下でよろしいですか?</span>
                    </div>
                    <br />
                    <div class="form-group">
                        <div class="row">
                            <label class="col-xl-1 d-flex align-items-center">
                                名前
                            </label>
                            <p class="col-xl-11" id="InputNameResult" />
                        </div>
                        <br />
                        <div class="row">
                            <label class="col-xl-1 d-flex align-items-center">
                                年齢
                            </label>
                            <p class="col-xl-11" id="InputAgeResult" />
                        </div>
                        <br />
                        <div class="row">
                            <label class="col-xl-1 d-flex align-items-center">
                                都道府県
                            </label>
                            <p class="col-xl-11" id="InputPrefResult" />
                        </div>
                        <br />
                        <div class="row">
                            <label class="col-xl-1 d-flex align-items-center">
                                地域
                            </label>
                            <p class="col-xl-11" id="InputAreaResult" />
                        </div>
                        <br />
                        <div class="row">
                            <label class="col-xl-1 d-flex align-items-center">
                                連絡先
                            </label>
                            <p class="col-xl-11" id="InputContactResult" />
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- jQuery -->
<script src="AdminLTE-3.0.2/plugins/jquery/jquery.min.js"></script>
<!-- Bootstrap 4 -->
<script src="AdminLTE-3.0.2/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- AdminLTE App -->
<script src="AdminLTE-3.0.2/js/adminlte.min.js"></script>

<script>
    function InputNameFunc(value) {
         document.getElementById("InputNameResult").innerHTML = value;
    }

</script>

</body>
</html>

できていないところは、言わずもがな確認画面。
今のソースだと、[基本]タブの「名前」に入力したテキストは、[確認]タブの「名前」に反映されるようになっている。
他の項目に対しても、あとは同じようなことをやれば確認画面は作れる。ここまできたら、ぶっちゃけもうそんなに時間もかからないと思う。

けど、いちいち項目ごとに

document.getElementById("InputNameResult").innerHTML = value;

みたいなコード書くのが究極にだるい。ついでに、保守性とか考えたらどうなんだろう、という感じ。

というわけで、こういうときはAzureのソースを見てみよう!
と思い、ジロジロソースを参照。すると、なんかやたら

<!-- /ko -->

みたいなコメントがあちこちにあることに気づく。なんだこれ・・・・と思って調べてみたら、
どうやら「knockout.js」というライブラリで使う表記(コメント)であることがわかった。
(実際にAzureがこれを使用しているのかは知らないが)

なので、ちょっとコレがなんなのか調べつつ、使えそうなら取り入れてみよう!と決意したぴよぴよくんであった・・・・

つづく(たぶん)

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