Проблема в написании программы для тестирования

245
12 ноября 2021, 13:50

Цель: пишу программу для тестирования, но в ней есть свои сложности, на решение которых пока не приходят мне в ум, у меня есть Treeview, в котором я создаю узлы с именем "Задание", также чуть выше имеется выбор тестирования их 3 т.е при выборе 1го типа тестирования я создаю узел и хочу, чтобы он открывал данную форму этого типа, при этом на кнопке "Добавить" программно создаются компоненты у каждого типа (Одиночный выбор, множ. выбор и сопоставление).

Слева появился узел и для него открылась форма в котором пользователь уже пишет свое задание, также добавить след. узел(задание) при этом 1ое задание сохранилось в *txt и так далее. В итоге хочу, чтобы все задания сохранились в 1 файл. Если вы знаете программу MyTestPro. а именно редактор там сделано также у меня(у меня чуть проще). Хочу подметить, что при нажатии на узел(задание), у меня создается клонирование(типа задания).

FileStream fs = new FileStream(@"D:\Новый файл.txt", FileMode.Create, FileAccess.Write);
        StreamWriter sw = new StreamWriter(fs);
        if (comboBox1.SelectedIndex == 0)
        {
            sw.WriteLine(lblNazvanie.Text);
            sw.WriteLine(EnterName.Text);
            sw.WriteLine(lblVopros.Text);
            sw.WriteLine(txtVopros.Text);
            sw.WriteLine(lblBalZaOtvet.Text);
            sw.WriteLine(domainUpDown.Text);
            sw.WriteLine(lblVar.Text);
            for (int i = 0; i < 6; i++)
                sw.WriteLine(txt[i].Text);
            for (int i = 0; i < 6; i++)
            {
                if (rb[i].Checked)
                    sw.WriteLine(rb[i].Text);
            }

Как делаю я: 1 при нажатии "добавить" у меня создается клон всех компонентов справа от treeview.

Проблема: он должен спросить (нужно ли сохранить?) сохраняю, но не закрывается сам вопрос(т.е. я могу позже к нему вернуться и если понадобиться отредактировать), а просто переходим к следующему и заданию и тд. а после все это сохр в файл.

Answer 1

Пример программирования вашей идеи.

Создадим классы предметной области

/// <summary>
/// Ответ
/// </summary>
public class Answer
{
    public string Value { get; set; }
    public bool IsCorrect { get; set; }
}
/// <summary>
/// Тип вопроса
/// </summary>
public enum QuestionType
{
    None,
    SingleSelect, //одиночный выбор
    MultipleSelect, //множественный выбор
}
/// <summary>
/// Вопрос
/// </summary>
public class Question
{
    public string Title { get; set; }
    public string Value { get; set; }
    public int Score { get; set; }
    public QuestionType Type { get; set; }
    public List<Answer> Answers { get; }
    public Question() : this(QuestionType.None)
    { }
    public Question(QuestionType questionType)
    {
        Type = questionType;
        Answers = new List<Answer>();
    }
}
/// <summary>
/// Задание
/// </summary>
public class Challenge
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Question> Questions { get; }
    public Challenge()
    {
        Questions = new List<Question>();
    }
}

Хранить данные программа будет в xml. Создадим для этого след. класс

/// <summary>
/// Контекст данных приложения
/// (запись/чтение данных в/из файла xml)
/// </summary>
public class DataContext
{
    //путь к файлу
    private readonly string _pathToFile;
    //задания
    private readonly List<Challenge> _сhallenges;
    /// <summary>
    /// Ctor Контекст данных приложения
    /// </summary>
    /// <param name="pathToFile">путь к файлу хранения данных программы</param>
    public DataContext(string pathToFile)
    {
        if (string.IsNullOrEmpty(pathToFile))
            throw new ArgumentException(nameof(pathToFile));
        _pathToFile = pathToFile;
        _сhallenges = new List<Challenge>();
        ReadFile();
    }
    /// <summary>
    /// Чтение из XML файла
    /// </summary>
    private void ReadFile()
    {
        var contents = String.Empty;
        if (File.Exists(_pathToFile))
        {
            contents = File.ReadAllText(_pathToFile);
        }
        if (String.IsNullOrEmpty(contents))
        {
            return;
        }
        var serializer = new XmlSerializer(_сhallenges.GetType());
        using (var reader = new StringReader(contents))
        {
            var records = (List<Challenge>)serializer.Deserialize(reader);
            _сhallenges.Clear();
            _сhallenges.AddRange(records);
        }
    }
    /// <summary>
    /// Запись в XML файл
    /// </summary>
    private void WriteFile()
    {
        var serializer = new XmlSerializer(_сhallenges.GetType());
        using (var writer = new StreamWriter(_pathToFile, false))
        {
            serializer.Serialize(writer, _сhallenges);
        }
    }
    /// <summary>
    /// Получить полный список заданий
    /// </summary>
    /// <returns></returns>
    public List<Challenge> GetAll()
    {
        return _сhallenges;
    }
    /// <summary>
    /// Добавить новое задание
    /// </summary>
    /// <param name="challenge"></param>
    public void AddChallenge(Challenge challenge)
    {
        if (challenge is null)
            throw new ArgumentNullException(nameof(challenge));
        if (_сhallenges.Count == 0)
        {
            challenge.Id = 1;
        }
        else
        {
            challenge.Id = _сhallenges.Max(c => c.Id) + 1;
        }
        _сhallenges.Add(challenge);
        WriteFile();
    }
    /// <summary>
    /// Получение задания
    /// </summary>
    /// <param name="name">имя задания</param>
    /// <returns>экземпляр задания</returns>
    public Challenge GetChallenge(string name)
    {
        //готовим результат
        var result = new Challenge();
        //ищем такую задачу
        var ch = _сhallenges.FirstOrDefault(c => c.Name.Equals(name));
        if (ch != null) result = ch;
        return result;
    }
    /// <summary>
    /// Получение вопроса
    /// </summary>
    /// <param name="challengeName">имя задания</param>
    /// <param name="questionName">название вопроса</param>
    /// <returns>экземпляр вопроса</returns>
    public Question GetQuestion(string challengeName, string questionName)
    {
        if (string.IsNullOrEmpty(challengeName))
            throw new ArgumentException(nameof(challengeName));
        if (string.IsNullOrEmpty(questionName))
            throw new ArgumentException(nameof(questionName));
        //готовим результат
        var result = new Question(QuestionType.None) { Title = "Не найден такой вопрос" };
        //ищем такую задачу
        var ch = _сhallenges.FirstOrDefault(c => c.Name.Equals(challengeName));
        if (ch is null) return result;
        //ищем такой вопрос
        var question = ch.Questions.FirstOrDefault(q => q.Title.Equals(questionName));
        if (question != null) result = question;
        return result;
    }
    /// <summary>
    /// Сохранение данных (с перечитыванием файла)
    /// </summary>
    public void Save()
    {
        WriteFile();
        ReadFile();
    }
}

Класс формы такой

public partial class FormMain : Form
{
    //контекст данных приложения
    private readonly DataContext _data;
    //для определения типа ноды кот.выделили
    private const string _Challenge_Node_Name = "Challenge";
    private const string _Question_Node_Name = "Question";
    //текущее задание и вопрос
    private Challenge _currentChallenge;
    private Question _currentQuestion;
    //список типов вопросов
    private List<QuestionTypeView> _types;
    //источники привязок
    private BindingSource _bsQuestion;
    private BindingSource _bsAnswers;
    public FormMain()
    {
        InitializeComponent();
        this.StartPosition = FormStartPosition.CenterScreen;
        this.Text = "Редактор тестов";
        //инициализация контекста данных
        _data = new DataContext("Data/challenges.xml");
        //привязки
        SetBindings();
        //подписка на события
        this.Load += FormMain_Load;
        _treeView.AfterSelect += TreeView_AfterSelect;
        _buttonSave.Click += ButtonSave_Click;
        _buttonQuestionAdd.Click += ButtonQuestionAdd_Click;
        _buttonQuestionDelete.Click += ButtonQuestionDelete_Click;
        _buttonChallengeAdd.Click += ButtonChallengeAdd_Click;
    }
    /// <summary>
    /// Установка привязок
    /// </summary>
    private void SetBindings()
    {
        //вопрос
        _bsQuestion = new BindingSource();
        _bsQuestion.DataSource = typeof(Question);
        //текстбоксы
        _textBoxTitle.DataBindings.Add("Text", _bsQuestion,
            nameof(Question.Title), true, DataSourceUpdateMode.OnPropertyChanged);
        _textBoxQuestion.DataBindings.Add("Text", _bsQuestion,
            nameof(Question.Value), true, DataSourceUpdateMode.OnPropertyChanged);
        _numericScore.DataBindings.Add("Value", _bsQuestion,
            nameof(Question.Score), true, DataSourceUpdateMode.OnPropertyChanged);
        //варианты ответов
        _bsAnswers = new BindingSource();
        _bsAnswers.DataSource = typeof(List<Answer>);
    }
    /// <summary>
    /// Форма загружена
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void FormMain_Load(object sender, EventArgs e)
    {
        SetComboBox();
        LoadChallenges();
    }
    /// <summary>
    /// Заполнение Комбобокса
    /// </summary>
    private void SetComboBox()
    {
        //комбобокс типов
        _types = QuestionTypeView.GetListTypes();
        _types.ForEach(t => _comboBoxType.Items.Add(t.Name));
    }
    /// <summary>
    /// Загрузка списка заданий
    /// </summary>
    private void LoadChallenges()
    {
        //читаем файл заданий
        var challenges = _data.GetAll();
        if (challenges.Count > 0)
        {
            _currentChallenge = challenges[0];
            ShowChallenges(challenges);
        }
    }
    /// <summary>
    /// Отображение заданий в TreeView
    /// </summary>
    /// <param name="challenges">список задач</param>
    private void ShowChallenges(List<Challenge> challenges)
    {
        //очищаем ранее отображаемое
        _treeView.Nodes.Clear();
        _currentQuestion = new Question(QuestionType.None);
        _bsQuestion.DataSource = new Question(QuestionType.None);
        _panel.Controls.Clear();
        foreach (Challenge challenge in challenges)
        {
            //создаем ноду задачи
            var node = new TreeNode(challenge.Name);
            node.Name = challenge.Name;
            node.Tag = _Challenge_Node_Name;
            foreach (Question question in challenge.Questions)
            {
                //создаем ноду вопроса
                var subNode = new TreeNode(question.Title);
                subNode.Name = question.Title;
                subNode.Tag = _Question_Node_Name;
                //добавляем в ноду задачи ноду вопроса
                node.Nodes.Add(subNode);
            }
            //добавляем ноду задачи в дерево
            _treeView.Nodes.Add(node);
        }
    }
    /// <summary>
    /// Выбрана нода в TreeView
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void TreeView_AfterSelect(object sender, TreeViewEventArgs e)
    {
        if (e.Node.Tag.ToString().Equals(_Challenge_Node_Name))
        {
            //получаем из контекста задание
            _currentChallenge = _data.GetChallenge(e.Node.Name);
            //убираем вопрос
            _bsQuestion.DataSource = new Question(QuestionType.None);
            _panel.Controls.Clear();
            return;
        }
        //извелкаем имена нод
        var challengeName = e.Node.Parent.Name;
        var questionName = e.Node.Name;
        //получаем из контекста задание
        _currentChallenge = _data.GetChallenge(challengeName);
        //получаем из контекста нужный вопрос
        _currentQuestion = _data.GetQuestion(challengeName, questionName);
        _bsQuestion.DataSource = _currentQuestion;
        _bsAnswers.DataSource = _currentQuestion.Answers;
        //отображаем этот вопрос
        ShowQuestion(_currentQuestion.Type);
    }
    /// <summary>
    /// Отобразить вопрос
    /// </summary>
    /// <param name="question">экземпляр вопроса</param>
    private void ShowQuestion(QuestionType type)
    {
        _panel.Controls.Clear();
        UserControl uc = new UserControl();
        if (type == QuestionType.SingleSelect)
        {
            uc = new UserControlSingle(_bsAnswers); 
        }
        if (type == QuestionType.MultipleSelect)
        {
            uc = new UserControlMulti(_bsAnswers);
        }
        _panel.Controls.Add(uc);
    }
    /// <summary>
    /// Кнопка Сохранить
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ButtonSave_Click(object sender, EventArgs e)
    {
        if (_currentQuestion.Type == QuestionType.None)
            return;
        //сохраняем в файл
        _data.Save();
        //перезагружаем задания
        LoadChallenges();
    }
    /// <summary>
    /// Кнопка Вопрос добавить
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ButtonQuestionAdd_Click(object sender, EventArgs e)
    {
        if (_currentChallenge is null)
            return;
        //получаем выбранный тип вопроса
        var selection = _comboBoxType.SelectedItem?.ToString();
        if (selection is null)
        {
            var message = "Выберите тип вопроса.";
            MessageBox.Show(message, "Сообщение",
                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return;
        }
        var type = _types.First(t => t.Name.Equals(selection)).Type;
        //новый вопрос добавляем в текущее задание
        var qTitle = "Новый вопрос";
        var question = GetNewQuestion(type, qTitle);
        _currentChallenge.Questions.Add(question);
        //запоминаем имя текущего задания
        var challengeName = _currentChallenge.Name;
        //перезагружаем задания
        LoadChallenges();
        SelectAddedNode(qTitle, challengeName);
    }
    /// <summary>
    /// Создание нового вопроса для добавления
    /// </summary>
    /// <param name="title">заголовок для вопроса</param>
    /// <returns>экземпляр вопроса</returns>
    private Question GetNewQuestion(QuestionType type, string title)
    {
        List<Answer> answers = new List<Answer>();
        for (int i = 0; i < 6; i++)
        {
            answers.Add(new Answer());
        }
        var result = new Question(type);
        result.Answers.AddRange(answers);
        result.Title = title;
        return result;
    }
    /// <summary>
    /// Выделение только что добавленной ноды вопроса
    /// </summary>
    /// <param name="title">заголовок вопроса</param>
    /// <param name="challengeName">имя задания</param>
    private void SelectAddedNode(string title, string challengeName)
    {
        //находим прежнюю ноду задания по названию
        var nodeChallenge = _treeView.Nodes.Find(challengeName, false).First();
        //находим ноду только что созданного вопроса и выделяем его
        var node = nodeChallenge.Nodes.Find(title, false).First();
        _treeView.SelectedNode = node;
        //выделяем текстбокс названия вопроса
        _textBoxTitle.Focus();
        _textBoxTitle.SelectAll();
    }
    /// <summary>
    /// Кнопка Вопрос удалить
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ButtonQuestionDelete_Click(object sender, EventArgs e)
    {
        if (_currentQuestion is null || _currentQuestion.Type == QuestionType.None)
            return;
        var isAgreed = UserAgreedDeleteQuestion();
        if (!isAgreed) return;
        //удаляем
        _currentChallenge.Questions.Remove(_currentQuestion);
        //сохраняем в файл
        _data.Save();
        //перезагружаем задания
        LoadChallenges();
    }
    /// <summary>
    /// Получение разрешения на удаление вопроса
    /// </summary>
    /// <returns>true если согласен</returns>
    private bool UserAgreedDeleteQuestion()
    {
        var message = $"Вы согласны удалить {_currentQuestion.Title}?";
        var caption = "Запрос на удаление вопроса";
        MessageBoxButtons buttons = MessageBoxButtons.YesNo;
        DialogResult result = System.Windows.Forms.DialogResult.Yes;
        return result == MessageBox.Show(message, caption, buttons, MessageBoxIcon.Question);
    }
    /// <summary>
    /// Кнопка Добавить задание
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ButtonChallengeAdd_Click(object sender, EventArgs e)
    {
        var str = "Наименование задания";
        var form = new FormChallenge();
        form.Owner = this;
        form.Name = str;
        if (form.ShowDialog() != DialogResult.OK)
            return;
        if (String.IsNullOrWhiteSpace(form.Name)
            || form.Name.Equals(str))
        {
            var message = "Для создания нового задания \nнеобходимо ввести его наименование.";
            MessageBox.Show(message, "Сообщение",
                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return;
        }
        var challenge = new Challenge();
        challenge.Name = form.Name;
        //coхраняем в файл
        _data.AddChallenge(challenge);
        //перезагружаем задания
        LoadChallenges();
    }
}

Полностью посмотреть пример можно здесь.

READ ALSO
Получить значение из Combobox, который внутри DataGrid WPF MVVM

Получить значение из Combobox, который внутри DataGrid WPF MVVM

Есть DataGrid, в ней несколько колонок, одна из них с ComboboxСписок для Combobox подгружаю из внешнего файла

335
Выполнить JS код в C#

Выполнить JS код в C#

Подскажите, пожалуйста, следующий момент

80
Добавить поддержку .fb2 в wordpress

Добавить поддержку .fb2 в wordpress

Собственно говоря как добавить поддержку форматаfb2 я пробовал добавить вот такой код в functions

104