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

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

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

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

WPF

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

Q&A

解決済

5回答

2689閲覧

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

Hottopia

総合スコア16

C#

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

WPF

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

1グッド

0クリップ

投稿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#

1 public class QuizData 2 { 3 public QuizData(string quizText, string[] choiceText, string answerText, string imgFilePath, string voiceFilePath) 4 { 5 QuestionText = quizText; 6 ChoiceText = choiceText; 7 AnswerText = answerText; 8 QuizImage = imgFilePath; 9 QuizVoice = voiceFilePath; 10 } 11 public string QuestionText = "";//テキスト(問題文) 12 public string[] ChoiceText = null;//テキストの配列(選択肢) 13 public string AnswerText = null;//テキスト(答え) 14 public string QuizImage = "";//ファイルパス(画像ファイルパス) 15 public string QuizVoice = "";//ファイルパス(音声ファイルパス) 16 } 17

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

C#

1public partial class MainWindow : Window 2{ 3 public List<QuizData> A_QuizData = new List<QuizData>(); //1要素につき、下記 QuizData classのインスタンスを格納 4 public List<QuizData> B_QuizData = new List<QuizData>(); //同上 5 public List<QuizData> C_QuizData = new List<QuizData>(); //同上 6 7 public void CreateQuizDataList() 8 { 9 string[] A_quizFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Question*.txt", SearchOption.AllDirectories); 10 string[] A_quizText = new string[A_quizFilePath.Length]; 11 for (var i = 0; i < A_quizFilePath.Length; i++) 12 { 13 A_quizText[i] = File.ReadAllText(A_quizFilePath[i]); 14 } 15 string[] A_answerFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Answer*.txt", SearchOption.AllDirectories); 16 for (var i = 0; i < A_answerFilePath.Length; i++) 17 { 18 var j = 0; 19 foreach (var line in File.ReadAllLines(A_answerFilePath[i])) 20 { 21 A_answerText[i, j] = line; 22 j++; 23 } 24 } 25 string[] A_imgFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Img*.jpg", SearchOption.AllDirectories); 26 27 string[] A_voiceFilePath = Directory.GetFiles(@"C:\Users...\category_A", "Question.mp3", SearchOption.AllDirectories); 28 for (var i = 0; i < A_quizFilePath.Length; i++) 29 { 30 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])); 31 } 32 }

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

C#

1 public partial class CategoryPage : Page 2 { 3 public CategoryPage() 4 { 5 InitializeComponent(); 6 } 7 8 private void ButtomAtA__Click(object sender, RoutedEventArgs e) //Quizページ遷移時、"A_"を渡す。 9 { 10 var category = "A_"; 11 var quiz = new Quiz(category); 12 NavigationService.Navigate(quiz); 13 } 14 private void ButtomAtB__Click(object sender, RoutedEventArgs e) //Quizページ遷移時、"B_"を渡す。 15 { 16 var category = "B_"; 17 var quiz = new Quiz(category); 18 NavigationService.Navigate(quiz); 19 } 20 private void ButtomAtC__Click(object sender, RoutedEventArgs e) //Quizページ遷移時、"C_"を渡す。 21 { 22 var category = "C_"; 23 var quiz = new Quiz(category); 24 NavigationService.Navigate(quiz); 25 } 26 }

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

C#

1public partial class Quiz : Page 2{ 3 readonly MainWindow _main = new MainWindow(); 4 private readonly string _category = ""; //switch分岐用. 5 public QuizPage(string category) 6 { 7 InitializeComponent(); 8 _category = category; //生成時、受け渡される "A" or "B" or "C". 9 ShuffleOrderQuizData(_category); 10 } 11 12 public void ShuffleOrderQuizData(string _category) 13 { 14 switch (_category) 15 { 16 case "A": 17 ShuffuleOrder_A_QuizData(); 18 break; 19 20 case "B": 21 ShuffleOrder_B_QuizData(); 22 break; 23 24 case "C": 25 ShuffleOrder_C_QuizData(); 26 break; 27 } 28 } 29 30 void ShuffuleOrderA_QuizData() 31 { 32 _main.A_QuizData = _main.A_QuizData.OrderBy(a => Guid.NewGuid()).ToList(); 33 for (var i = 0; i < _main.A_QuizData.Count; i++) 34 { 35 _main.A_QuizData[i].ChoiceText = _main.A_QuizData[i].ChoiceText.OrderBy(a => Guid.NewGuid()).ToArray(); 36 } 37 } 38 39 void ShuffleOrderB_QuizData() 40 { 41 _main.B_QuizData = _main.B_QuizData.OrderBy(a => Guid.NewGuid()).ToList(); 42 for (var i = 0; i < _main.B_QuizData.Count; i++) 43 { 44 _main.B_QuizData[i].ChoiceText = _main.B_QuizData[i].ChoiceText.OrderBy(a => Guid.NewGuid()).ToArray(); 45 } 46 } 47 48 void ShuffleOrderC_QuizData() 49 { 50 _main.C_QuizData = _main.C_QuizData.OrderBy(a => Guid.NewGuid()).ToList(); 51 for (var i = 0; i < _main.C_QuizData.Count; i++) 52 { 53 _main.C_QuizData[i].ChoiceText = _main.C_QuizData[i].ChoiceText.OrderBy(a => Guid.NewGuid()).ToArray(); 54 } 55 } 56}

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

TN8001👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/11/25 03:12 編集

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

2021/11/25 03:16

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

退会済みユーザー

2021/11/25 03:44 編集

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

2021/11/25 03:24

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

退会済みユーザー

2021/11/25 03:30

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

退会済みユーザー

2021/11/25 03:43 編集

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

2021/11/25 03:55

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

退会済みユーザー

2021/11/25 04:10 編集

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

2021/11/25 06:16 編集

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

退会済みユーザー

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クラスを使っている画面を指しているのでしょうか。コードが断片的で、質問者さんの意図が正確に伝わらないのだと思います。(私もいまだ、分かりません)
退会済みユーザー

退会済みユーザー

2021/11/25 09:04

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

2021/11/25 23:36

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

回答5

0

ベストアンサー

たくさん回答も付いてるうえBAもされているようですが^^;

結局やりたいことって「問題の順番・選択肢の順番をランダムにしたい」ということですよね?
難しく考えすぎというか、外野であれこれしようとしすぎというか。

今回の場合は単に取得時に、都度シャッフルした配列・リストを返せばいいだけに見えます。
カテゴリもなぜ文字列で渡さなければならないかが、コードから読み取れません(リスト自体を渡せばいいだけでは?)

xamlがわからないので何とも言えませんが、ItemsControl等をうまく使うとコレクション内の個数を気にせず表示できます(回答は選択肢だけで使っていますが、カテゴリでも同じように作れます)

コードがないとイメージしにくそうなので、非常に雑ですがサンプルです(ファイル云々は省略)

MainWindow

xml

1<NavigationWindow 2 x:Class="Questions370911.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Width="800" 6 Height="450" 7 ShowsNavigationUI="False" 8 Source="/CategoryPage.xaml" />

cs

1using System; 2using System.Collections.Generic; 3using System.Linq; 4 5namespace Questions370911 6{ 7 public class QuizData 8 { 9 public string Question { get; } 10 11 // プロパティにして取得のたびにシャッフルした配列を返す 12 public string[] Choices 13 { 14 get 15 { 16 return _Choices.OrderBy(_ => Guid.NewGuid()).ToArray(); 17 } 18 } 19 // ↑↓同じ意味 20 //public string[] Choices => _Choices.OrderBy(_ => Guid.NewGuid()).ToArray(); 21 22 public string Answer { get; } 23 24 private readonly string[] _Choices; 25 26 public QuizData(string question, params string[] choices) 27 { 28 Question = question; 29 _Choices = choices; 30 Answer = choices[0]; 31 } 32 } 33 34 35 public partial class MainWindow // : Window 36 { 37 // ここも 38 public List<QuizData> A_QuizData => _A_QuizData.OrderBy(_ => Guid.NewGuid()).ToList(); 39 public List<QuizData> B_QuizData => _B_QuizData.OrderBy(_ => Guid.NewGuid()).ToList(); 40 public List<QuizData> C_QuizData => _C_QuizData.OrderBy(_ => Guid.NewGuid()).ToList(); 41 42 private readonly List<QuizData> _A_QuizData = new List<QuizData> 43 { 44 new QuizData("史上初の家庭用ゲーム機とされるものは?", "オデッセイ(マグナボックス)", "ホーム・ポン(アタリ)", "カラーテレビゲーム15(任天堂)"), 45 new QuizData("ファミコンのコントローラーにはマイクが付いている?", "○", "×"), 46 new QuizData("スーパーファミコンソフト「ドラゴンクエスト6 幻の大地」の定価(税抜)は?", "11,400円", "14,800円", "9,700円", "5,980円"), 47 new QuizData("PlayStationの同時発売ソフトは?", "リッジレーサー(ナムコ)", "モータートゥーン・グランプリ(SCE)", "チョロQ(タカラ)"), 48 }; 49 private readonly List<QuizData> _B_QuizData = new List<QuizData> 50 { 51 new QuizData("hogehoge", "A", "B", "C"), 52 }; 53 private readonly List<QuizData> _C_QuizData = new List<QuizData> 54 { 55 new QuizData("fugafuga", "1", "2", "3", "4"), 56 }; 57 58 59 public MainWindow() => InitializeComponent(); 60 } 61}

CategoryPage

xml

1<Page 2 x:Class="Questions370911.CategoryPage" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 5 <UniformGrid Columns="3"> 6 <Button Click="ButtonA_Click" Content="おじさんゲーマークイズ" /> 7 <Button Click="ButtonB_Click" Content="hogehoge" /> 8 <Button Click="ButtonC_Click" Content="fugafuga" /> 9 </UniformGrid> 10</Page>

cs

1using System.Windows; 2using System.Windows.Controls; 3using System.Windows.Navigation; 4 5namespace Questions370911 6{ 7 public partial class CategoryPage : Page 8 { 9 // こうしてしまうと「今」表示しているMainWindowとは別のMainWindowを作ってしまっている! 10 //readonly MainWindow _main = new MainWindow(); 11 private readonly MainWindow _main; 12 13 public CategoryPage() 14 { 15 InitializeComponent(); 16 17 // 手軽にやるならこう 18 _main = (MainWindow)Application.Current.MainWindow; 19 } 20 21 private void ButtonA_Click(object sender, RoutedEventArgs e) 22 => NavigationService.Navigate(new QuizPage(_main.A_QuizData)); 23 private void ButtonB_Click(object sender, RoutedEventArgs e) 24 => NavigationService.Navigate(new QuizPage(_main.B_QuizData)); 25 private void ButtonC_Click(object sender, RoutedEventArgs e) 26 => NavigationService.Navigate(new QuizPage(_main.C_QuizData)); 27 } 28}

QuizPage

xml

1<Page 2 x:Class="Questions370911.QuizPage" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 7 d:DesignHeight="450" 8 d:DesignWidth="800" 9 mc:Ignorable="d"> 10 <Page.Resources> 11 <Style TargetType="TextBlock"> 12 <Setter Property="HorizontalAlignment" Value="Center" /> 13 <Setter Property="VerticalAlignment" Value="Center" /> 14 </Style> 15 <Style TargetType="Button"> 16 <Setter Property="HorizontalAlignment" Value="Center" /> 17 <Setter Property="VerticalAlignment" Value="Center" /> 18 </Style> 19 </Page.Resources> 20 <Grid> 21 <!-- 22 TabControlを使った深い意味はありません。 23 比較的シンプルでデザインも確認しやすいって程度です。 24 --> 25 <TabControl x:Name="tabControl" BorderThickness="0"> 26 <TabItem Header="問題" Visibility="Collapsed"> 27 <Grid> 28 <Grid.RowDefinitions> 29 <RowDefinition /> 30 <RowDefinition /> 31 </Grid.RowDefinitions> 32 <TextBlock x:Name="questionTextBlock" Text="問題文" /> 33 <ItemsControl 34 x:Name="itemsControl" 35 Grid.Row="1" 36 HorizontalAlignment="Center" 37 VerticalAlignment="Center" 38 d:ItemsSource="{d:SampleData}" 39 Button.Click="AnswerButton_Click"> 40 <ItemsControl.ItemsPanel> 41 <ItemsPanelTemplate> 42 <WrapPanel /> 43 </ItemsPanelTemplate> 44 </ItemsControl.ItemsPanel> 45 <ItemsControl.ItemTemplate> 46 <DataTemplate> 47 <Button Margin="5" Content="{Binding}" /> 48 </DataTemplate> 49 </ItemsControl.ItemTemplate> 50 </ItemsControl> 51 </Grid> 52 </TabItem> 53 54 <TabItem Header="正解" Visibility="Collapsed"> 55 <Grid> 56 <Grid.RowDefinitions> 57 <RowDefinition /> 58 <RowDefinition /> 59 </Grid.RowDefinitions> 60 <TextBlock Text="正解" /> 61 <Button 62 Grid.Row="1" 63 Click="NextButton_Click" 64 Content="次へ" /> 65 </Grid> 66 </TabItem> 67 68 <TabItem Header="不正解" Visibility="Collapsed"> 69 <Grid> 70 <Grid.RowDefinitions> 71 <RowDefinition /> 72 <RowDefinition /> 73 </Grid.RowDefinitions> 74 <TextBlock Text="不正解" /> 75 <Button 76 Grid.Row="1" 77 Click="NextButton_Click" 78 Content="次へ" /> 79 </Grid> 80 </TabItem> 81 82 <TabItem Header="成績" Visibility="Collapsed"> 83 <Grid> 84 <Grid.RowDefinitions> 85 <RowDefinition /> 86 <RowDefinition /> 87 </Grid.RowDefinitions> 88 <TextBlock x:Name="resultTextBlock" Text="〇問中〇問正解" /> 89 <Button 90 Grid.Row="1" 91 Click="BackButton_Click" 92 Content="戻る" /> 93 </Grid> 94 </TabItem> 95 </TabControl> 96 </Grid> 97</Page>

cs

1using System; 2using System.Collections.Generic; 3using System.Windows; 4using System.Windows.Controls; 5using System.Windows.Navigation; 6 7namespace Questions370911 8{ 9 public partial class QuizPage : Page 10 { 11 private readonly List<QuizData> quizData; 12 private int index; 13 private int correct; 14 15 // わざわざ文字列でカテゴリを渡すより、直接リストをもらったほうが早いでしょう 16 // カテゴリ名も欲しければ、KOZ6.0さんの回答のようにクラスにまとめましょう 17 public QuizPage(List<QuizData> quizData) 18 { 19 InitializeComponent(); 20 21 this.quizData = quizData; 22 23 questionTextBlock.Text = quizData[index].Question; 24 itemsControl.ItemsSource = quizData[index].Choices; 25 tabControl.SelectedIndex = 0; 26 } 27 28 private void AnswerButton_Click(object sender, RoutedEventArgs e) 29 { 30 if (e.OriginalSource is Button button) 31 { 32 if ((string)button.Content == quizData[index].Answer) 33 { 34 tabControl.SelectedIndex = 1; 35 correct++; 36 } 37 else 38 { 39 tabControl.SelectedIndex = 2; 40 } 41 42 index++; 43 } 44 } 45 46 private void NextButton_Click(object sender, RoutedEventArgs e) 47 { 48 if (index < quizData.Count) 49 { 50 questionTextBlock.Text = quizData[index].Question; 51 itemsControl.ItemsSource = quizData[index].Choices; 52 tabControl.SelectedIndex = 0; 53 } 54 else 55 { 56 resultTextBlock.Text = $"{quizData.Count}問中{correct}問正解"; 57 tabControl.SelectedIndex = 3; 58 } 59 } 60 61 private void BackButton_Click(object sender, RoutedEventArgs e) 62 => NavigationService.Navigate(new Uri("/CategoryPage.xaml", UriKind.Relative)); 63 } 64}

アプリ動画


それより_main = new MainWindow();のほうが気になります。
表示しているMainWindowとは別のMainWindowを作ってしまっています。
これでは無駄に何度もファイルを読むことになります。

投稿2021/11/25 08:46

編集2023/07/29 09:21
TN8001

総合スコア9321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2021/11/25 08:47

個人的にはNavigationWindowやFrameは、挙動が独特(ブラウザ寄り)すぎて好きじゃないですね。 特に↓の「イヤな点」が嫌すぎます。 [WPFでシンプルな独自ナビゲーション処理のサンプルを書いてみた - SourceChord](https://sourcechord.hatenablog.com/entry/2016/02/01/003758 「じゃあどうすんだ?」と言われると、これと言ってベストな解があるわけでもないんですが^^;
Hottopia

2021/11/25 23:49

まさに、ページ遷移の方法についても、不便さを感じていました。リンクまで貼っていただいてありがとうございます。
guest

0

正直,意味がよくわからないが……

「CategoryPage でどのボタンが押されたか?」次第で,以降の処理で取り扱うべきデータの種類(category)が定まる

のであれば,それ以降(categoryが定まって以降)に生成される Quiz とか MainWindow とかいうやつらは,その特定のcategoryのデータのみを用意して扱えば良いのではないのでしょうか?

すなわち,そもそも
A_QuizData, B_QuizData, C_QuizData という3つのListを保有する意味はないのでは?
Listは単独で良く,単にそのListに選ばれたcategoryに相当するデータファイルを読み込んでやればよいだけでは.

投稿2021/11/25 08:08

編集2021/11/25 08:10
fana

総合スコア11656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/11/25 08:20

極端なことを言えば,CategoryPage の各ボタンのイベントにて, new Quiz( そのカテゴリ用のファイル群があるディレクトリのパス ); とかいう形のことをするとしたら, Quiz は MainWindow にこのパスをそのまま渡せばよく, MainWindow は渡されたこのパスを用いて,単一のカテゴリ用のデータを List に読み込めばよく, Quiz は MainWindow が保有している List を単にいじくりまわせばいい. Quiz も MainWindow も,「選択された Category は何なのか?」なんてことは全く把握していないし,把握する必要もないのでは.
Hottopia

2021/11/25 08:32

皆様ご回答ありがとうございました、 もっと質問を整理して出直します。なんとなく理想に一番近い気がしたので、fana様をベストアンサーとさせて頂きます。質問力など技量が足らず混乱させてしまったかと思います。すみませんでした。
fana

2021/11/25 08:43 編集

考えの整理がついてからベストアンサーを選ぶのでも良いのでは…という気がします. 一旦この質問は閉じて仕切り直したいのだとしても, 他の既存回答の 意味/意義 などを踏まえたうえで閉じ方を判断するのが良いでしょう. コメントを拝見するに他回答の内容をデータ構造の話としか見えていない様子とも見受けますが, そもそもデータ構造が変わればそれを扱う処理コード(「遷移時のやり方」等)も相応に変わる(というか,変えることができる)わけですから,少し考えてみてはどうでしょうか. 仮にそれらのデータ構造を採用したならば,あなたのコードはどうなるだろうか? というのを.
guest

0

QuizDataにカテゴリを含めてしまえば、このような事が出来ます。

cs

1using System; 2using System.Linq; 3using System.Collections.Generic; 4 5public class QuizData 6{ 7 public QuizData(string category, string quizText) 8 { 9 Category = category; 10 QuestionText = quizText; 11 } 12 public string Category { get; } //カテゴリ 13 public string QuestionText { get; } //テキスト(問題文) 14} 15 16class Program 17{ 18 19 static void Main() 20 { 21 //テストデータ作成(カテゴリは A,B,C,A,B,C…となる) 22 var listQuiz = new List<QuizData>(); 23 for( int i = 0; i<10; i++ ) 24 { 25 listQuiz.Add( 26 new QuizData( 27 ((char)('A' + (i % 3))).ToString(), 28 $"QuestionText{i}" 29 ) 30 ); 31 } 32 33 //カテゴリをKey、そのカテゴリに含まれるQuizDataのListをValueとするDictionaryを作成 34 var dictQuiz = listQuiz.ToLookup(quiz => quiz.Category) 35 .ToDictionary(quiz => quiz.Key, quiz => quiz.ToList()); 36 37 //カテゴリ一覧を出力 38 foreach (var key in dictQuiz.Keys) 39 { 40 Console.WriteLine($"Category:{key}"); 41 } 42 43 //カテゴリ"B"のクイズを出力 44 foreach(var quiz in dictQuiz["B"]) 45 { 46 Console.WriteLine($"QuizData(Category, QuestionText):{quiz.Category}, {quiz.QuestionText}"); 47 } 48 49 Console.ReadKey(); 50 } 51} 52 53(出力結果) 54Category:A 55Category:B 56Category:C 57QuizData(Category, QuestionText):B, QuestionText1 58QuizData(Category, QuestionText):B, QuestionText4 59QuizData(Category, QuestionText):B, QuestionText7

投稿2021/11/25 05:31

編集2021/11/25 05:35
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんな感じですべてのクイズを持たせる Dictionary を作れば良いのでは?

C#

1public Dictionary<string, List<QuizData>> All_QuizData 2 = new Dictionary<string, List<QuizData>>(); 3 4All_QuizData["A_"] = A_QuizData; 5All_QuizData["B_"] = B_QuizData; 6All_QuizData["C_"] = C_QuizData;

ShuffleOrderQuizData(string _category) は

C#

1public void ShuffleOrderQuizData(string _category) { 2 List<QuizData> target = _main.All_QuizData[_category]; 3 target = target.OrderBy(a => Guid.NewGuid()).ToList(); 4 for (var i = 0; i < target.Count; i++) { 5 target[i].ChoiceText = target[i].ChoiceText.OrderBy(a => Guid.NewGuid()).ToArray(); 6 } 7}

のような感じになります。

私だったら List<QuizData> の部分は、以下のようなクラスを作って置き換えるかも。

C#

1public class QuizDataList : List<QuizData> 2{ 3 public string Category { get; } 4 public QuizDataList(string category) { 5 Category = category; 6 } 7}

投稿2021/11/25 04:35

KOZ6.0

総合スコア2626

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Hottopia

2021/11/25 07:49

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

0

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>(); //同上

って、List<QuizData>のリストにすればいいのでは
数値(変数)でアクセスできますよ

投稿2021/11/25 03:10

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Hottopia

2021/11/25 07:49

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問