質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

解決済

【C#】ページ遷移時の処理について。分岐方式を改善したい。

Hottopia
Hottopia

総合スコア3

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

5回答

-2評価

1クリップ

886閲覧

投稿2021/11/25 02:55

編集2021/11/25 07:46

#前提・実現したいこと
C# WPFにてクイズゲームを開発しています。
以下のコードを改善したいです。
プログラムの内容としては、

【mainクラス】

  1. ローカルファイルからテキスト、画像、音声ファイルパスを取得する。
  2. txtファイルはテキストに変換、jpg,mp3ファイルはファイルパスのままstring型変数に格納
    し、インスタンス化、これをListの1要素とする。
  3. 1,2,をフォルダ内に存在する分繰り返す。

※カテゴリーごとにA_フォルダ、B_フォルダ,C_フォルダで分かれており、
A_フォルダはA_List,B_フォルダはB_List,C_フォルダはC_Listに格納

【categoryクラス】

  1. ボタンが3つあり、それぞれのクリックイベントでquizクラスページに遷移。

遷移時に渡すパラメータにより、カテゴリーを識別、対応したListを操作。

【quizクラス】

  1. mainクラスのListを参照し、要素の順番と、要素内 配列 の順番をシャッフルする。
  2. 対応したコントロールのプロパティに代入。

長いコードなので、コードの内容を説明しながら、改善したい箇所を書いていきたいと思います。

まず、次のような、テキスト、ファイルパスを格納するためのクラスがあります。

C#

public class QuizData { public QuizData(string quizText, string[] choiceText, string answerText, string imgFilePath, string voiceFilePath) { QuestionText = quizText; ChoiceText = choiceText; AnswerText = answerText; QuizImage = imgFilePath; QuizVoice = voiceFilePath; } public string QuestionText = "";//テキスト(問題文) public string[] ChoiceText = null;//テキストの配列(選択肢) public string AnswerText = null;//テキスト(答え) public string QuizImage = "";//ファイルパス(画像ファイルパス) public string QuizVoice = "";//ファイルパス(音声ファイルパス) }

下記のコードは、ローカルファイルからテキスト、ファイルパスを取得し、上記QuizDataクラスに格納、1問ずつインスタンス化してListに格納するコードです。

C#

public partial class MainWindow : Window { public List<QuizData> A_QuizData = new List<QuizData>(); //1要素につき、下記 QuizData classのインスタンスを格納 public List<QuizData> B_QuizData = new List<QuizData>(); //同上 public List<QuizData> C_QuizData = new List<QuizData>(); //同上 public void CreateQuizDataList() { string[] A_quizFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Question*.txt", SearchOption.AllDirectories); string[] A_quizText = new string[A_quizFilePath.Length]; for (var i = 0; i < A_quizFilePath.Length; i++) { A_quizText[i] = File.ReadAllText(A_quizFilePath[i]); } string[] A_answerFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Answer*.txt", SearchOption.AllDirectories); for (var i = 0; i < A_answerFilePath.Length; i++) { var j = 0; foreach (var line in File.ReadAllLines(A_answerFilePath[i])) { A_answerText[i, j] = line; j++; } } string[] A_imgFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Img*.jpg", SearchOption.AllDirectories); string[] A_voiceFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Question.mp3", SearchOption.AllDirectories); for (var i = 0; i < A_quizFilePath.Length; i++) { A_QuizData.Add(new QuizData(A_quizText[i], new string[] { A_answerText[i, 0], A_answerText[i, 1], A_answerText[i, 2] }, A_answerText[i, 3], A_imgFilePath[i], A_voiceFilePath[i])); } }

次は、カテゴリー選択画面についてのコードです。
押下されたボタンによってカテゴリーを決定し、遷移先のページは同一のものですが、
遷移時に渡すパラメータによって、表示する内容が変化します。

C#

public partial class CategoryPage : Page { public CategoryPage() { InitializeComponent(); } private void ButtomAtA__Click(object sender, RoutedEventArgs e) //Quizページ遷移時、"A_"を渡す。 { var category = "A_"; var quiz = new Quiz(category); NavigationService.Navigate(quiz); } private void ButtomAtB__Click(object sender, RoutedEventArgs e) //Quizページ遷移時、"B_"を渡す。 { var category = "B_"; var quiz = new Quiz(category); NavigationService.Navigate(quiz); } private void ButtomAtC__Click(object sender, RoutedEventArgs e) //Quizページ遷移時、"C_"を渡す。 { var category = "C_"; var quiz = new Quiz(category); NavigationService.Navigate(quiz); } }

次が、改善したいコードとなります。
下記のQuizクラスは、mainクラスを生成し、List要素の順番と、要素内の
string[] choiceText の順番をランダムにシャッフルし、画面に表示するものですが、
3つあるうちのListのどれをシャッフルするかを、switch文にて指定している形になっています。

C#

public partial class Quiz : Page { readonly MainWindow _main = new MainWindow(); private readonly string _category = ""; //switch分岐用. public QuizPage(string category) { InitializeComponent(); _category = category; //生成時、受け渡される "A" or "B" or "C". ShuffleOrderQuizData(_category); } public void ShuffleOrderQuizData(string _category) { switch (_category) { case "A": ShuffuleOrder_A_QuizData(); break; case "B": ShuffleOrder_B_QuizData(); break; case "C": ShuffleOrder_C_QuizData(); break; } } void ShuffuleOrderA_QuizData() { _main.A_QuizData = _main.A_QuizData.OrderBy(a => Guid.NewGuid()).ToList(); for (var i = 0; i < _main.A_QuizData.Count; i++) { _main.A_QuizData[i].ChoiceText = _main.A_QuizData[i].ChoiceText.OrderBy(a => Guid.NewGuid()).ToArray(); } } void ShuffleOrderB_QuizData() { _main.B_QuizData = _main.B_QuizData.OrderBy(a => Guid.NewGuid()).ToList(); for (var i = 0; i < _main.B_QuizData.Count; i++) { _main.B_QuizData[i].ChoiceText = _main.B_QuizData[i].ChoiceText.OrderBy(a => Guid.NewGuid()).ToArray(); } } void ShuffleOrderC_QuizData() { _main.C_QuizData = _main.C_QuizData.OrderBy(a => Guid.NewGuid()).ToList(); for (var i = 0; i < _main.C_QuizData.Count; i++) { _main.C_QuizData[i].ChoiceText = _main.C_QuizData[i].ChoiceText.OrderBy(a => Guid.NewGuid()).ToArray(); } } }

質問するに至った経緯ですが、現状だと、項目が増えた場合や処理に変更があった場合などに、caseひとつひとつを修正しなければならないことと、インスタンスに引数を持たせ、遷移先のコンストラクタで分岐する、というやり方が、適切ではないように感じたためです。
開発経験が浅い為、的外れかもしれませんが、どのように改善すればよいか、ご意見を頂けないでしょうか。
宜しくお願い致します。
##追記・修正
質問の仕方が悪く、申し訳ありませんでした。
おもにお聞きしたい内容としては、「ページ遷移時、インスタンスに引数を持たせ、遷移先のコンストラクタで分岐する」というやり方について、別の方法があるならばご教示頂きたい。といったものがメインとなります。
このやり方が最適ではないように感じ、調べたところstateパターンというのが理想に近いと感じましたが、具体的な実装方法に詰まってしまい、教えて頂きたく、質問を致しました。

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

SurferOnWww

2021/11/25 03:12 編集

単なる思い付きですが、 (1) テキスト、画像、音声ファイルパスにカテゴリー列を追加してデータベースに格納する(データベースとかは使いたくないなら例えば CSV ファイルに格納する) (2) データベースから DISTINCT を使ってカテゴリーを取得し ComboBox で表示し、それからユーザーに選択してもらう。 (3) ユーザーのカテゴリー選択結果に基づき、データベースからそのカテゴリーに属するレコードをすべて取得する。 (4) 上記 (3) の結果を処理して出題する。
Hottopia

2021/11/25 03:16

こんにちは。 条件等記載し忘れていましたが、DB,CSVは使えず、ローカルファイルでの構築が前提となっております。 ですが考え方については参考にさせていただきます。ありがとうございます。
SurferOnWww

2021/11/25 03:44 編集

ローカルファイルに CSV は含まれるはず。CSV って何だかわかってますか? ただのテキストファイルですよ。 何かの理由で CSV を使いたくないとしても、ローカルファイルなら XML でも JSON でも使えるはず。
Hottopia

2021/11/25 03:24

失礼しました。 テキストはtxtファイル、画像はjpg、音声はmp3、という指定です。 混乱させてしまい申し訳ありません。
SurferOnWww

2021/11/25 03:30

あなたの言うカテゴリーには増減があるから今回のような質問になっていると思いますが、そうであればそのカテゴリーを質問のようにコードの中にハードコーディングしてしまっては、増減があるたびコードを書き直さなければならないのはやむを得ません。そういうことをしなくて済む提案をしているつもりですけど、理解してもらっているでしょうか?
SurferOnWww

2021/11/25 03:43 編集

例えば、 カテゴリー,テキストファイルのパス,画像ファイルのパス,音声ファイルのパス というデータをその数 CSV ファイルに格納しておくということはできないのですか? それさえできれば、上に述べた (1) ~ (4) はできるはずで、switch 文のハードコーディングは避けられると思いますけど。
Hottopia

2021/11/25 03:55

理解力が足らず申し訳ありません。 現状の.txtファイルで問題文・選択肢・回答テキストを管理する方法は好ましくなく、CSVファイルで取り扱ったほうが色々と便利ということでしょうか。 一点教えて頂きたいのですが、CSV形式でデータを管理する場合、画像ファイル・音声ファイルはファイルパスとしてCSVファイルに格納するということでしょうか?
SurferOnWww

2021/11/25 04:10 編集

> 現状の.txtファイルで問題文・選択肢・回答テキストを管理する方法は好ましくなく、CSVファイルで取り扱ったほうが色々と便利ということでしょうか。 その「.txtファイル」というのは、質問に書いてあった、 > 1. ローカルファイルからテキスト、画像、音声ファイルパスを取得する。 の「ローカルファイル」のことですよね。その内容がどうなっているのか不明ですが上に私が書いた「テキストファイルのパス,画像ファイルのパス,音声ファイルのパス」の情報は含まれているのではないですか? であれば、それに「カテゴリー」を追加して形式を以下のようにし、 カテゴリー,テキストファイルのパス,画像ファイルのパス,音声ファイルのパス<改行> それを必要な数だけ複数行作る、すなわち CSV 形式にすることは可能だと思うのですが。それができれば CSV ファイルを読んできて List<T> 型のオブジェクトを作成して、Linq を使って扱うのが便利で、switch 文のハードコーディングを避けるという目的も果たせると思いますけど。
Hottopia

2021/11/25 06:16 編集

お付き合いいただきありがとうございます。 今回は、「インスタンスに引数を持たせ、遷移先のコンストラクタで分岐する。」というやり方が、適切ではないように感じていた為、この場にて皆様のご意見を伺っておりました。 今回のプログラムについては、問題文等のテキストリソースは全てメモ帳で作成し、txtファイルで管理したい、という要望があったため、このような形式にこだわっていました。 このようなローカルファイルでデータを管理するようなケースでは、SurferOnWww様のおっしゃるようにCSVファイルでの管理が適切なようですので、そういった設計にしたい思います。私自身不勉強で、説明能力も足りていませんでしたが、丁寧に教えてくださってありがとうございました。
SurferOnWww

2021/11/25 06:53

> 今回は、「インスタンスに引数を持たせ、遷移先のコンストラクタで分岐する。」というやり方が、適切ではないように感じていた為、この場にて皆様のご意見を伺っておりました。 意味不明です。話が変わって来てませんか? タイトルに「switch文による分岐を改修したい」とあって、現状ハードコーディングしてある switch 文をカテゴリーの増減によって書き直さなくても済むようにしたいという話ではなかったのですか? どうもお互い話が通じなかったみたいですね。
退会済みユーザー

退会済みユーザー

2021/11/25 07:24 編集

とりあえず回答いくつか出てますが、放置せずに回答の内容で解決するのか、解決しないのであればその理由を書くか、何かコメントつけたらどうですか?回答した人に失礼ですよ。
Hottopia

2021/11/25 07:37

SurferOnWww様  質問を見返してみましたが、確かにそう受け取られてしまう書き方だったと思います。修正しました。
Hottopia

2021/11/25 07:49

radian様 失礼致しました。質問に追記をしましたが、データ構造についてもお聞きしたいとは思っていましたが、メインであるのは遷移時のやり方についてです。お手を煩わせてしまい申し訳ありませんでした。
Zuishin

2021/11/25 07:56

「遷移時のやり方」が何を意味しているのかわかりません。私には十分な回答が出ているように見えるので、何に引っかかっているのかをもう少し具体的に質問した方がいいと思います。
退会済みユーザー

退会済みユーザー

2021/11/25 08:08 編集

結局どういう回答を期待しているのかさっぱり分からないのですが。 [質問するときのヒント] https://teratail.com/help/question-tips ここの2と3を読んでください。 回答者はエスパーではないので、疑問点やどういう答えが欲しいかを相手に判るように具体的に伝えないと期待した答えは返せません。
ozwk

2021/11/25 08:13 編集

(勘違いのため削除)
dodox86

2021/11/25 08:33

Zuishinさんと同意見。いただいている回答を理解すればクローズするかと思ったのですが、そうでもないのですね。「遷移」という言葉が出てきていますが、これは画面遷移のことでしょうか。「カテゴリー選択画面」という言葉が質問中にありますね。ページとは、Pageクラスを使っている画面を指しているのでしょうか。コードが断片的で、質問者さんの意図が正確に伝わらないのだと思います。(私もいまだ、分かりません)
SurferOnWww

2021/11/25 09:04

次回質問することがあるなら、ぜひこれをよく読んでからにしてください⇒ https://teratail.com/help/question-tips 特にこのあたり: "人に質問をするには、自分が何を尋ねたいかを知っている必要があります。これは、「自分が今『何がわからないのか』がわかっていて、言語化できている」ということです。一見簡単なようですが、実はとても難しいことです。何がわからないかわからない人から質問を受けても、答える側も困ってしまいます。"
Hottopia

2021/11/25 23:36

はい、自分でも、途中から何を伝えたいのか、意味の伝わらない質問を重ねてしまっていたと反省しております。。 精進します。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです