您好,我正在尝试构建一个测验应用程序来构建一个测验应用程序,其中将从我项目中的数据文件夹中名为 cbt.db 的 sqlite 数据库中检索问题。但是,每当我运行该应用程序时,它都会返回以下错误:“System.ArgumentOutOfRangeException:'索引超出范围。必须为非负数且小于集合的大小。(参数'索引')'”在行中QuizViewModel 中有
currentQuestion = Questions[_currentQuestionIndex];
。我尝试将 _currentQuestionIndex 设置为 1,但仍然不起作用。我只想在处理测验逻辑之前用第一个问题填充标签。
数据库结构如下:
有一个问题表,其中有一个从1开始的question_id和question_text字段。还有一个答案表,其中也有 Question_id、answer_id、answer_text 和 is_ Correct 字段。 answer_id 适用于每个单独的答案,其中 Question_id 映射到问题表的答案。
这是我的模型类:Question.cs
using ColumnAttribute = SQLite.ColumnAttribute;
namespace CBT.Models;
public class Question
{
[Column("question_id")]
public int Id { get; set; }
[Column("question_text")]
public string? QuestionText { get; set; }
[Column("category_id")]
public int CategoryID { get; set; }
public List<Answer>? Answers { get; set; }
}
public class Answer
{
[Column("question_id")]
public int Id { get; set; }
[Column("answer_id")]
public int AnswerID { get; set; }
[Column("answer_text")]
public string? AnswerText { get; set; }
[Column("is_correct")]
public bool IsCorrect { get; set; }
}
这是 DBService 接口:IDBService.cs
namespace CBT.Services;
public interface IDBService
{
Task<List<Question>> GetQuestionsAsync();
Task<Question> GetQuestionAsync(int id);
Task<int> SaveQuestionAsync(Question question);
Task<int> DeleteQuestionAsync(int id);
Task<List<Answer>> GetAnswersAsync();
Task<Answer> GetAnswerAsync(int id);
}
这是DBService.cs
using CBT.Models;
namespace CBT.Services;
class DBService : IDBService
{
// The database connection object
public static SQLiteAsyncConnection? database;
// Get the database path from the app data directory
public static string DBPath { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CBT_App.Data.cbt.db");
// The constructor initializes the database connection and creates the table if not exists
public DBService()
{
// Create the table for the question model class if not exists
database.CreateTableAsync<Question>();
// Create the table for the answer model class if not exists
database.CreateTableAsync<Answer>();
}
// This method returns a list of all items in the database
public async Task<List<Question>> GetQuestionsAsync()
{
return await database.Table<Question>().ToListAsync();
}
public async Task<List<Answer>> GetAnswersAsync()
{
return await database.Table<Answer>().ToListAsync();
}
// This method returns a specific item by its id
public async Task<Question> GetQuestionAsync(int id)
{
return await database.Table<Question>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
public async Task<Answer> GetAnswerAsync(int id)
{
return await database.Table<Answer>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
// This method inserts a new item or updates an existing one
public async Task<int> SaveQuestionAsync(Question question)
{
if (question.Id != 0)
{
// Update an existing item
return await database.UpdateAsync(question);
}
else
{
// Insert a new item
return await database.InsertAsync(question);
}
}
// This method deletes an item by its id
public async Task<int> DeleteQuestionAsync(int id)
{
return await database.DeleteAsync<Question>(id);
}
}
这是App.xaml.cs
namespace CBT;
public partial class App : Application
{
public App()
{
if(!File.Exists(DBService.DBPath))
{
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly;
using Stream? stream = assembly.GetManifestResourceStream("CBT.Data.cbt.db");
using MemoryStream? memoryStream = new();
stream.CopyTo(memoryStream);
File.WriteAllBytes(DBService.DBPath, memoryStream.ToArray());
}
DBService.database = new SQLiteAsyncConnection(DBService.DBPath, Constants.Flags);
InitializeComponent();
MainPage = new AppShell();
}
}
这是 QuizViewModel.cs
namespace CBT.ViewModels;
public partial class QuizViewModel : ObservableObject
{
readonly IDBService dbService;
private int _currentQuestionIndex;
private int _currentAnswerIndex;
public ObservableCollection<Question> Questions { get; } = [];
//public Question? currentQuestion => Questions[_currentQuestionIndex];
public ObservableCollection<Answer> Answers { get; } = [];
//public Answer currentAnswer => Answers[_currentAnswerIndex];
[ObservableProperty]
public Question currentQuestion;
[ObservableProperty]
public Answer currentAnswer;
[ObservableProperty]
public string? currentAnswerText;
[ObservableProperty]
public bool currentAnswerIsCorrect;
public QuizViewModel(IDBService dBService)
{
this.dbService = dBService;
Task getQuestionsAsync = GetQuestionsAsync();
Task getAnswersAsync = GetAnswersAsync();
currentQuestion = Questions[_currentQuestionIndex];
currentAnswer = Answers[_currentAnswerIndex];
currentAnswerText = CurrentQuestion.Answers[_currentAnswerIndex].AnswerText;
currentAnswerIsCorrect = CurrentQuestion.Answers[_currentAnswerIndex].IsCorrect;
NextQuestion();
NextAnswers();
}
[RelayCommand]
async Task GetQuestionsAsync()
{
try
{
var questions = await dbService.GetQuestionsAsync();
if(questions.Count != 0)
{
Questions.Clear();
}
foreach(var question in questions)
{
Questions.Add(question);
}
}
catch(Exception ex)
{
Debug.Print($"Unable to get questions: {ex.Message}");
}
}
[RelayCommand]
async Task GetAnswersAsync()
{
try
{
var answers = await dbService.GetAnswersAsync();
if (answers.Count != 0)
{
Answers.Clear();
}
foreach (var answer in answers)
{
Answers.Add(answer);
}
}
catch (Exception ex)
{
Debug.Print($"Unable to get answers: {ex.Message}");
}
}
[RelayCommand]
private void NextQuestion()
{
if (_currentQuestionIndex < Questions.Count - 1)
{
_currentQuestionIndex++;
_currentAnswerIndex = 0;
}
}
[RelayCommand]
private void NextAnswers()
{
if (_currentAnswerIndex < CurrentQuestion.Answers.Count - 1)
{
_currentAnswerIndex ++;
}
}
}
测验页面.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CBT.Views.QuizPage"
Title="QuizPage"
xmlns:vm="clr-namespace:CBT.ViewModels"
xmlns:model="clr-namespace:CBT.Models"
x:DataType="vm:QuizViewModel">
<VerticalStackLayout>
<Label x:Name="questionLabel"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label x:Name="answer1Label"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label x:Name="answer2Label"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label x:Name="answer3Label"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label x:Name="answer4Label"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
测验页面.xaml.cs
namespace CBT.Views;
public partial class QuizPage : ContentPage
{
public QuizPage(QuizViewModel quizViewModel)
{
InitializeComponent();
Populate(quizViewModel);
}
public void Populate(QuizViewModel quizViewModel)
{
questionLabel.Text = quizViewModel.CurrentQuestion.QuestionText;
}
}
AppShell.xaml
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="CBT.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:CBT.Views"
xmlns:local="clr-namespace:CBT">
<ShellContent
Shell.NavBarIsVisible="true"
Title="Main"
Icon="iconblank.png"
ContentTemplate="{DataTemplate views:QuizPage}"
Route="QuizPage" />
</Shell>
常量.cs
namespace CBT
{
public static class Constants
{
public const SQLiteOpenFlags Flags =
// open the database in read/write mode
SQLiteOpenFlags.ReadWrite |
// create the database if it doesn't exist
SQLiteOpenFlags.Create |
// enable multi-threaded database access
SQLiteOpenFlags.SharedCache;
}
}
MauiProgram.cs
namespace CBT;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>().UseMauiCommunityToolkitCore();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
builder.Services.AddSingleton<IDBService, DBService>();
builder.Services.AddSingleton<INavigationService, NavigationService>();
builder.Services.AddSingleton<MainViewModel>();
builder.Services.AddSingleton<MainPage>();
builder.Services.AddTransient<QuizViewModel>();
builder.Services.AddTransient<QuizPage>();
return builder.Build();
}
}
GlobalUsings.cs
global using CommunityToolkit.Mvvm.ComponentModel;
global using CommunityToolkit.Mvvm.Input;
global using CBT.ViewModels;
global using CBT.Views;
global using CBT.Models;
global using CBT.Services;
global using System.Collections.ObjectModel;
global using System.ComponentModel;
global using System.Diagnostics;
global using System.Globalization;
global using System.Runtime.CompilerServices;
global using System.Text.Json;
global using System.Threading.Tasks;
global using System;
global using System.Reflection;
global using System.Collections.Generic;
global using System.Linq;
global using System.Text;
global using SQLite;
global using CommunityToolkit.Maui;
global using CommunityToolkit.Maui.Core;
System.ArgumentOutOfRangeException:'索引超出范围。必须是 非负且小于集合的大小。 (范围 'index')'" 行中有 currentQuestion = 问题[_currentQuestionIndex];在 QuizViewModel 中
错误原因是列表中没有index(
_currentQuestionIndex
)值的项目。
并且从您分享的代码中,我们可以发现您想要使用代码
Questions
访问currentQuestion = Questions[_currentQuestionIndex];
中的元素,但是此时Questions
并没有代码 Task getQuestionsAsync = GetQuestionsAsync();
之后的元素。这行代码 currentAnswer = Answers[_currentAnswerIndex];
也很有可能有这个问题
public QuizViewModel(IDBService dBService)
{
this.dbService = dBService;
Task getQuestionsAsync = GetQuestionsAsync();
Task getAnswersAsync = GetAnswersAsync();
currentQuestion = Questions[_currentQuestionIndex];
currentAnswer = Answers[_currentAnswerIndex];
currentAnswerText = CurrentQuestion.Answers[_currentAnswerIndex].AnswerText;
currentAnswerIsCorrect = CurrentQuestion.Answers[_currentAnswerIndex].IsCorrect;
}