業務のためのC#・C言語・C++学習

主にC#の文法やWPF周りのアウトプットに利用してます。

【C#-文法】Dictionaryの初期化

Dictionaryの初期化は2つの方法がある。 1つはブラケット構文、もう1つはAddメソッドの利用である。

ブラケット構文によるDictionary初期化

        static void Main(string[] args)
        {
            //ブラケット構文による初期化
            var dic = new Dictionary<string, string>()
            {
                ["Red"] = "赤",
                ["Blue"] = "青",
                ["Green"] = "緑"
            };

            //表示
            foreach (var key in dic.Keys)
            {
                Console.WriteLine($"{key} : {dic[key]}");
            }
            //結果
            //Red : 赤
            //Blue : 青
            //Green : 緑
        }

AddメソッドによるDictionary初期化

            var dic1 = new Dictionary<string, string>();
            dic1.Add("Red", "赤");
            dic1.Add("Blue", "青");
            dic1.Add("Green", "緑");

            //表示
            foreach (var key in dic1.Keys)
            {
                Console.WriteLine($"{key} : {dic1[key]}");
            }

Dictionaryに値を追加・上書きする方法は以下を参照。

gaishiengineer.hatenablog.com

【C#-WPF】ViewModelで写真付きポップアップを表示するには

目標
・ボタンをクリックしたら適当な写真付きポップアップを表示したい
//以下省略 ・ポップアップにはコマンドボタンを実装したい
・ポップアップに実装するボタンによりtrue/false判断をしたい。trueであれば次に進みfalseであればキャンセルしたい

課題
・写真をどう利用すればよいのか?
MVVMパターンの中にポップアップの実装は可能か?
・ポップアップは一般的に親クラスのViewと関係(=Owner)を持つ必要がある

写真利用について
まず適当な写真を用意しフォルダに追加する

BitmapImageクラスを利用する
https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media.imaging.bitmapimage?view=windowsdesktop-7.0

        public void Popup()
        {
            //写真のパスを指定
            var path = @"\Image\direction.png";
            //create source
            var bitmap = new BitmapImage();
            //BitmapImage.UriSource must be in a BeginInit/EndInit block.
            bitmap.BeginInit();
            //bitmapプロパティの設定はここでする
            bitmap.UriSource = new Uri(path,UriKind.Relative);
            bitmap.EndInit();

        }

プロパティの変更は、オブジェクトの初期化中にのみ実行できます。 BeginInit を呼び出して初期化が開始されたことを通知し、EndInit を呼び出して初期化が完了したことを通知します。 初期化後、プロパティの変更は無視されます。

UriKind.Relativeについて
今回は相対パスを利用している。

MVVMパターンで写真付きのポップアップ実装について
ViewModel:
・ボタンコマンドRunを実装
・ポップアップ設定するクラスを呼び出しShowDialog()で表示

    public class MainWindowViewModel
    {
        private ICommand _run;
        public ICommand Run
        {
            get
            {
                if (_run == null)
                {
                    _run = new Command(() => { Popup(); });
                }
                return _run;
            }
        }
        public void Popup()
        {
            //写真のパスを指定
            var path = @"\Image\direction.png";
            //create source
            var bitmap = new BitmapImage();
            //BitmapImage.UriSource must be in a BeginInit/EndInit block.
            bitmap.BeginInit();
            //bitmapプロパティの設定はここでする
            bitmap.UriSource = new Uri(path, UriKind.Relative);
            bitmap.EndInit();

            //ポップアップを作成
            var popup = new Popupwindow()
            {
                //ポップアップの設定をする
                Source = bitmap,
            };
            //ポップアップを表示する
            popup.ShowDialog();
        }
    }
    public class Command : ICommand
    {
        Action _action;
        public Command(Action action)
        {
            _action = action;
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _action();
        }
    }

ポップアップのxaml

    <DockPanel>
        <DockPanel>
            <Image Source="{Binding Source}" x:Name="Image"/>
        </DockPanel>
    </DockPanel>

ポップアップのコードビハインド

    public partial class Popupwindow : Window
    {
        public Popupwindow()
        {
            InitializeComponent();
        }

        public ImageSource Source
        {
            set { Image.Source = value; }
        }
    }

実行結果

ポップアップに親クラスのViewと関係(=Owner)を持たせるには

MainWindowViewModelのコンストラクタでViewと関連付ける

public class MainWindowViewModel
    {
        public MainWindowViewModel(MainWindow parent)
        {
            _parent = parent;
        }
        private readonly MainWindow _parent;
        public MainWindow Parent { get { return _parent; } }

        private ICommand _run;
        public ICommand Run
        {
            get
            {
                if (_run == null)
                {
                    _run = new Command(() => { Popup(); });
                }
                return _run;
            }
        }
        public void Popup()
        {
            //写真のパスを指定
            var path = @"\Image\direction.png";
            //create source
            var bitmap = new BitmapImage();
            //BitmapImage.UriSource must be in a BeginInit/EndInit block.
            bitmap.BeginInit();
            //bitmapプロパティの設定はここでする
            bitmap.UriSource = new Uri(path, UriKind.Relative);
            bitmap.EndInit();

            //ポップアップを作成
            var popup = new Popupwindow()
            {
                //ポップアップの設定をする
                Owner = Parent,
                Source = bitmap,
            };
            //ポップアップを表示する
            popup.ShowDialog();
        }
    }

【C#-WPF】アプリケーション設定

WPFGUIを立ち上げたり閉じる際に何かしらの変数を参照してGUIに反映したいとする。この時方法はいくつかあるが、その内の一つがアプリケーション設定”Properties.Settings.Default”の利用である。

アプリケーション設定”Properties.Settings.Default”の利用方法について述べる。

初期値の設定

適当なWPFプロジェクトを新規で作成

プロジェクトを右クリックしプロパティを開く

Setting画面を開く

適当な値を設定する。

”Properties.Settings.Default”設定値の利用

Setting画面で設定したNameをProperties.Settings.Default.AとProperties.Settings.Default.Bのように利用可能。

        public MainWindow()
        {
            InitializeComponent();
            textBlockA.Text = Properties.Settings.Default.A;
            textBlockB.Text= Properties.Settings.Default.B;
        }

出力結果

”Properties.Settings.Default”設定値の上書き方法

Properties.Settings.Default.Save();を用いる。

        public MainWindow()
        {
            InitializeComponent();
            textBlockA.Text = Properties.Settings.Default.A;
            textBlockB.Text= Properties.Settings.Default.B;

            Properties.Settings.Default.A = "New A";
            Properties.Settings.Default.B = "New B";
            Properties.Settings.Default.Save();
            textBlockA.Text = Properties.Settings.Default.A;
            textBlockB.Text = Properties.Settings.Default.B;
        }

【C#】文字列から文字を一部抜き取る

文字列の中から文字列を抜き取る場合はSubstringメソッドを利用する。
文字列の中から1文字だけを抜き取る場合はブラケット構文を利用する。

Sunstringの利用方法を挙げる。
Sunstring(抜き取り開始位置, 抜き取る文字列の長さ)

            string a = "0123456789";
            var b = a.Substring(0, 3);
            Console.Write(b);

出力結果
012

抜き取り開始位置だけを指定する場合

            string a = "0123456789";
            var b = a.Substring(0);
            Console.Write(b);

出力結果
0123456789

ブラケット構文の利用方法をあげる。

            string a = "0123456789";
            var c = a[1];
            Console.WriteLine(c);

出力結果
1

【C#】第二回アルゴリズム検定実技検定 過去問解答例

Aエレベータ

問題

下から順に B9, B8, ..., B1, 1F, 2F, ..., 9F と呼ばれる 18 のフロアを持つ建物があります。 この建物のエレベーターは、隣接する 2 つのフロア間の移動に常に 1 秒を要します。例えば、B9 から 9F への移動には 17 秒を要し、反対方向も同様です。 2 つのフロア S, T が与えられます。エレベーターが S から T へ移動するには最短で何秒を要するでしょうか。

解法

フロア名から階数、地下階、地上階かを判断するため文字列の切り取りをするインデクサー[]を利用。 地下と地上の移動時間の算出には、階数の引き算では0階がないためうまくいかない。そこで地下の階数にあえて+1を加える。

            var input = Console.ReadLine().Split();
            var s = input[0];
            var t = input[1];

            int si=0;
            if (s[0] == 'B')
            {
                si = -int.Parse(s[1].ToString())+1;
            }
            else if(s[1] == 'F')
            {
                si = int.Parse(s[0].ToString());
            }

            int ti=0;
            if (t[0] == 'B')
            {
                ti = -int.Parse(t[1].ToString())+1;
            }
            else if (t[1] == 'F')
            {
                ti = int.Parse(t[0].ToString());
            }
            var result = Math.Abs(si - ti);
            Console.WriteLine(result);

B多数決

文字列の切り取りをするインデクサー[]を利用

問題

ある国で選挙が行われました。候補者は a, b, c の 3 名です。

投票されたすべての票を表す文字列 S が与えられます。 S は英小文字 a, b, c からなり、 S の i 文字目は i 番目の投票者が投票した候補者を表します。最多得票を得た候補者は誰か求めてください。

なお、最多得票を得た人物はちょうど 1 名であることが保証されています。

解法
            var s = Console.ReadLine();

            int counta = 0;
            int countb = 0;
            int countc = 0;
            for (int i = 0; i < s.Length; i++)
            {
                if (s[i].ToString() == "a")
                {
                    counta++;
                }
                else if (s[i].ToString() == "b")
                {
                    countb++;
                }
                else { countc++; }
            }
            if (counta > countb && counta > countc)
            {
                Console.WriteLine('a');
            }
            else if (countb > counta && countb > countc)
            {
                Console.WriteLine('b');
            }
            else { Console.WriteLine('c'); }

C

ジャグ配列の操作を行う。
ジャグ配列はまず行の要素数を決めその後に列の要素数を決める。

問題

https://atcoder.jp/contests/past202004-open/tasks/past202004_c

        static void Main(string[] args)
        {
            var N = int.Parse(Console.ReadLine());
            string[][] S = new string[N][];
            for (int i = 0; i < N; i++)
            {
                S[i] = new string[2 * N - 1];
                var input = Console.ReadLine();
                for (int j = 0; j < 2 * N - 1; j++)
                {
                    S[i][j] = input[j].ToString();
                }
            }


            for (int i = N-2; i >= 0; i--)
            {
                for (int j = 1; j < 2 * N - 2; j++)
                {
                    if (S[i][j] == "#")
                    {
                        
                        if (S[i + 1][j - 1] == "X" || S[i + 1][j] == "X" || S[i + 1][j + 1] == "X")//
                        {
                            S[i][j] = "X";
                        }
                    }
                }

            }

            for (int i = 0; i < N; i++)
            {
                for (int j = 0; j < 2 * N - 1; j++)
                {
                    Console.Write(S[i][j]);
                }
                Console.WriteLine("");
            }

        }

【C#-WPF】MVVMパターンの基礎

MVVMパターンとは、データ(ロジック)とUI機能を分離するデザインパターンの一種で、開発やデバッグを効率的に行えるメリットがある。一方MVVMパターンを導入するが故に構成が複雑になるデメリットである。
WPFMicrosoftによってMVVMパターンを導入することを目的としたUIフレームワークである。したがって、WPFではMVVMパターンを採用することが多い。ここがMVVMパターンが必要ないWindows Formsと大きく異なる点だが、残念ながらWPFMVVMパターンで簡潔に説明した書籍がないため初学者には学習しづらい環境になっている。(誰か出版してください)

アプリケーション構造

MVVMパターンは、アプリケーションの構造をView、ViewModel、Modelと3分割する。

View

アプリのユーザーが目で確認できるUI部分つまりデザイン。XAMLで定義する。Windows、テキストボックス、アニメーションなど。Binding実装する必要がある。

Model

データ(ロジック)を処理する部分。例えばデータベースから何かしらのデータを持ってきて計算しその結果を返す機能を持たせたり、組込み機器の制御機能をここに実装する。
Modelは必ずしも必要ではなく、小規模なアプリケーションであればModelの内容をViewModelにコーディングする場合もある。

ViewModel

Viewに表示するデータを渡す部分
ViewとViewModelはDataContextを用い連携する。
InotifyPropertyChangedやINotifyCollectionChangedを実装する必要がある。

MVVMパターンの最小構成

まず話を簡潔にするためにModelがない構成で説明する。1番シンプルな構成で学習する方が概要を掴むのに効率がよい。

View実装

Viewにはbindingを用い実装する
下記コードはTextBlock の表示を実装している。
View(XAML)でbinding宣言

<TextBlock Text="{Binding Path=TextName}"/>

ViewModelの実装

ViewModelではView(XAML)で定義したTextNameをプロパティとして定義

    public class ViewModel
    {
        public string TextName { get; set; }
    }

ViewとViewModelの連携

コードビハインドでViewModelのインスタンスを作りDataContextにSetする。
* WPFのコードビハインドは、XAMLと呼ばれるXMLベースのマークアップ言語で作成されたUI要素と、C#で書かれたロジックとを結びつけるためのファイルです。XAMLはUIのデザインや構造を定義し、コードビハインドはそのUI要素に対するイベント処理や動的な振る舞いを定義します。
以下の例ではTextNameに初期値"MVVMパターン"を代入した。

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var vm = new ViewModel();
            vm.TextName = "MVVMパターン";

            DataContext = vm;

        }

    }

Modelの実装

今回は省略

MVVMパターンにInotifyPropertyChangedを実装

ViewModelの実装

前節ではViewのコンストラクタでViewModelのプロパティに変数を代入後、DataContextにViewModelのインスタンスを代入した。これによりViewの変更を行った。
プロパティの変更をDataContext利用時以降もしくはコンストラクタ以外で行う汎用的なアプリケーションにするためには、InotifyPropertyChangedをViewModelに実装する必要がある。

public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        private string _textname = "";// 初期値
        public string TextName
        {
            get { return _textname; }
            set
            {
                if (_textname != value)
                {
                    _textname = value;
                    RaisePropertyChanged("TextName");
                }
            }
        }


    }

ViewとViewModelの連携

プロパティTextNameに値を変更すればViewに変更通知行き表示内容も変わる。

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
   InitializeComponent();
            //ViewModelのクラスからプロパティを設定しUIに反映させる
            var vm = new ViewModel();

            //プロパティの初期値
            vm.TextName = "MVVMパターン";
            this.DataContext = vm;
            

            //プロパティのUpdate
            vm.TextName = "MVVMパターンその2";
        }

    }

【C#-文法】多次元配列の基礎 配列に配列を入れる

多次元配列について記述する。
多次元配列の特徴は縦と横の長さが等しくある。等しくない配列はジャグ配列という。

2次元配列

【1】初期値を指定した宣言

            int[,] data = new[,]
            {
                { 10,11,12},
                { 20,21,22},
                { 30,31,32},
            };

行列として表現

【2】配列のサイズだけを宣言

            int[,] data1 = new int[3, 3];

行列として表現

3次元配列

【1】初期値を指定した宣言

            int[,,] data = new[,,]
            {
               {
                { 000,001,002},
                { 010,011,012},
                { 020,021,022},
               },
               {
                { 100,101,102},
                { 110,111,112},
                { 120,121,122},
               },
               {
                { 200,201,202},
                { 210,211,212},
                { 220,221,222},
               },
            };

行列として表現

【2】配列のサイズだけを宣言

            int[,,] data1 = new int[3, 3,3];