Цель: пишу программу для тестирования, но в ней есть свои сложности, на решение которых пока не приходят мне в ум, у меня есть 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.
Проблема: он должен спросить (нужно ли сохранить?) сохраняю, но не закрывается сам вопрос(т.е. я могу позже к нему вернуться и если понадобиться отредактировать), а просто переходим к следующему и заданию и тд. а после все это сохр в файл.
Пример программирования вашей идеи.
Создадим классы предметной области
/// <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();
}
}
Полностью посмотреть пример можно здесь.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть DataGrid, в ней несколько колонок, одна из них с ComboboxСписок для Combobox подгружаю из внешнего файла
Собственно говоря как добавить поддержку форматаfb2 я пробовал добавить вот такой код в functions