Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.78/130: Рейтинг темы: голосов - 130, средняя оценка - 4.78
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2

Пример создания приложения для тестирования [WPF, Элд Хасп]

13.06.2019, 22:43. Показов 28658. Ответов 24
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Тема из цикла Готовые решения, примеры и рекомендации начинающим на WPF [Элд Хасп]

Пример практической реализации приложения для тестирования по мотивам темы Где можно глянуть примеры создания теста? от ahtik95.

1) Создание XML структуры

Сначала создал XML для хранения теста Test.xml
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0"?>
<Test>
  <NameTest>Самый лучший тест!</NameTest>
  <Questions>
    <Question IsOnlyOne="true">
      <Text>Три минус два</Text>
      <Answers>
        <Answer IsRight="true">Один</Answer>
        <Answer IsRight="false">Два</Answer>
      </Answers>
    </Question>
    <Question IsOnlyOne="true">
      <Text>Дважды два</Text>
      <Answers>
        <Answer IsRight="false">Три</Answer>
        <Answer IsRight="true">Четыре</Answer>
        <Answer IsRight="false">Пять</Answer>
      </Answers>
    </Question>
    <Question IsOnlyOne="false">
      <Text>Трижды два</Text>
      <Answers>
        <Answer IsRight="true">Больше трёх</Answer>
        <Answer IsRight="false">Больше шести</Answer>
        <Answer IsRight="true">Меньше девяти</Answer>
      </Answers>
    </Question>
  </Questions>
</Test>
Корневой тег теста <Test/>
Тест имеет тег для названия <NameTest/> и тег для вопросов теста <Questions/>.

В теге <Questions/> содержится список тегов <Question/> для информации об одном вопросе.
Атрибут IsOnlyOne обозначает тип вопроса: true - только с одним правильным ответом, false - с разным количеством правильных ответов.

Тег <Answers/> содержит список вариантов ответов.
Вариант ответа содержится в теге <Answer/>. Атрибут ответа IsRight обозначает правильный или ложный ответ. Значение тега - текст ответа.

2) Классы для десериализации XML

По этой XML структуре через конструктор VS (Меню -> Правка -> Специальная вставка -> Вставить XML как классы) были созданы классы для десериализации этого XML. Полученные классы после "косметической" доводки
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
namespace TestWPF
{
    // Примечание. Для запуска созданного кода может потребоваться NET Framework версии 4.5 или более поздней версии и .NET Core или Standard версии 2.0 или более поздней.
    /// <summary>Класс теста Модели</summary>
    [Serializable()]
    [System.ComponentModel.DesignerCategory("code")]
    [XmlType(AnonymousType = true)]
    [XmlRoot(Namespace = "", IsNullable = false, ElementName ="Test")]
    public partial class TestClass
    {
 
        /// <summary>Название теста</summary>
        public string NameTest { get; set; }
 
        /// <summary>Вопросы теста</summary>
        [XmlArrayItem("Question", IsNullable = false)]
        public TestClassQuestion[] Questions { get; set; }
    }
 
    /// <summary>Класс вопроса Модели</summary>
    [Serializable()]
    [System.ComponentModel.DesignerCategory("code")]
    [XmlType(AnonymousType = true)]
    public partial class TestClassQuestion
    {
 
        /// <summary>Текст вопроса</summary>
        public string Text { get; set; }
 
        /// <summary>Тип вопроса: <see langword="true"/> - только один ответ правильный,
        /// <see langword="false"/> - несколько вопросов могут быть правильными</summary>
        [XmlAttribute()]
        public bool IsOnlyOne { get; set; }
 
        /// <summary>Варианты ответов на вопрос</summary>
        [XmlArrayItem("Answer", IsNullable = false)]
        public TestClassAnswer[] Answers { get; set; }
    }
 
    /// <summary>Класс ответа на вопрос Модели</summary>
    [Serializable()]
    [System.ComponentModel.DesignerCategory("code")]
    [XmlType(AnonymousType = true)]
    public partial class TestClassAnswer
    {
 
        /// <summary>Флаг верного ответа</summary>
        [XmlAttribute()]
        public bool IsRight { get; set; }
 
        /// <summary>Текст ответа</summary>
        [XmlText()]
        public string Text { get; set; }
    }
}
3) Модель
Модель очень простая. В конструкторе происходит десериализация XML и проверка на ошибки. Два свойства: одно - для хранения теста, второе - для названия файла из которого был загружен тест.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    public class Model
    {
        /// <summary>Загруженный тест</summary>
        public TestClass Test { get; }
 
        /// <summary>Имя файла из которого загружен тест</summary>
        public string NameFileTest { get; }
 
        /// <summary>Конструтор с заданием имени файла из которого нужно загрузить тест</summary>
        /// <param name="nameFileTest">Имя файла теста</param>
        public Model(string nameFileTest)
        {
            XmlSerializer ser = new XmlSerializer(typeof(TestClass));
            using (FileStream file = new FileStream(nameFileTest, FileMode.Open))
            {
                Test = (TestClass)ser.Deserialize(file);
            }
            NameFileTest = nameFileTest;
 
            foreach (TestClassQuestion question in Test.Questions)
            {
                int countRight = question.Answers.Count(ans => ans.IsRight);
                if (countRight == 0)
                    throw new TestException("Хоть один ответ должен быть правильным!", question, TestExceptionEnum.NoRight);
                if (countRight != 1 && question.IsOnlyOne)
                    throw new TestException("Для этого вопроса только один ответ должен быть правильным!", question, TestExceptionEnum.NotOnlyOne);
            }
        }
        /// <summary>Конструтор без параметров. Загружает тест из файла "Test.xml"</summary>
        public Model() : this("Test.xml") { }
    }
Для исключений создал тип исключения TestException
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    public class TestException : Exception
    {
        /// <summary>Вопрос теста в котором ошибка</summary>
        public TestClassQuestion Question { get; }
 
        /// <summary>Тип ошибки</summary>
        public TestExceptionEnum Error { get; }
 
        #region Конструторы с различным набором параметров
        public TestException(TestClassQuestion question, TestExceptionEnum error)
        {
            Question = question;
            Error = error;
        }
        public TestException(string message, TestClassQuestion question, TestExceptionEnum error)
            : base(message)
        {
            Question = question;
            Error = error;
        }
        public TestException(string message, Exception innerException, TestClassQuestion question, TestExceptionEnum error)
            : base(message, innerException)
        {
            Question = question;
            Error = error;
        }
        #endregion
    }
И так же перечисление для указания типа ошибки
C#
1
2
3
4
5
6
7
8
9
    public enum TestExceptionEnum
    {
        /// <summary>Нет правильных ответов</summary>
        NoRight,
        /// <summary>Правильный должен быть только один ответ</summary>
        NotOnlyOne,
        /// <summary>Неверное значение свойства IsOnlyOne</summary>
        InvalidIsOnlyOne
    }
4) Классы для команд и реализации INPC

Использую в самых простых реализациях
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
namespace TestWPF
{
    #region Делегаты для методов WPF команд
    public delegate void ExecuteHandler(object parameter);
    public delegate bool CanExecuteHandler(object parameter);
    #endregion
 
    /// <summary>Класс реализующий интерфейс ICommand для создания WPF команд</summary>
    public class RelayCommand : ICommand
    {
        private readonly CanExecuteHandler _canExecute;
        private readonly ExecuteHandler _onExecute;
 
        /// <summary>Событие извещающее об изменении состояния команды</summary>
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
 
        /// <summary>Конструктор команды</summary>
        /// <param name="execute">Выполняемый метод команды</param>
        /// <param name="canExecute">Метод разрешающий выполнение команды</param>
        public RelayCommand(ExecuteHandler execute, CanExecuteHandler canExecute = null)
        {
            this._onExecute = execute;
            this._canExecute = canExecute;
        }
 
 
        /// <summary>Вызов разрешающего метода команды</summary>
        /// <param name="parameter">Параметр команды</param>
        /// <returns>True - если выполнение команды разрешено</returns>
        public bool CanExecute(object parameter) => _canExecute == null ? true : _canExecute.Invoke(parameter);
 
        /// <summary>Вызов выполняющего метода команды</summary>
        /// <param name="parameter">Параметр команды</param>
        public void Execute(object parameter) => _onExecute?.Invoke(parameter);
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace TestWPF
{
    /// <summary>Базовый класс с реализацией INPC </summary>
    public abstract class OnPropertyChangedClass : INotifyPropertyChanged
    {
        /// <summary>Событие для извещения об изменения свойства</summary>
        public event PropertyChangedEventHandler PropertyChanged;
 
        /// <summary>Метод для вызова события извещения об изменении свойства</summary>
        /// <param name="propertyName">Изменившееся свойство</param>
        public void OnPropertyChanged([CallerMemberName]string propertyName = "") =>
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
5
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
13.06.2019, 22:43
Ответы с готовыми решениями:

Пример создания приложения "Работа с комнатами в студенческих общежитиях" [WPF, SQLite, Элд Хасп]
Тема из цикла https://www.cyberforum.ru/wpf-silverlight/thread2384523.html Создана как продолжение темы...

WPF vs WinForms (для начинающих) [Элд Хасп]
Тема из цикла https://www.cyberforum.ru/wpf-silverlight/thread2384523.html Эту тему решил создать, так как очень часто сталкиваюсь с...

WPF команды и MVVM. Часть 2. Всплытие команд. Реализация команды для списка элементов [WPF, Элд Хасп]
Тема из цикла https://www.cyberforum.ru/wpf-silverlight/thread2384523.html На практике часто встречаются случаи когда команда и кнопка...

24
0 / 0 / 0
Регистрация: 05.05.2020
Сообщений: 35
18.04.2022, 17:46
Студворк — интернет-сервис помощи студентам
Спасибо за ответ
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Bellatrix27, и насколько это "серьёзное" приложение?
Приложение имеет минимальный уровень серьёзности. Обычное задание, которое положено было выполнять на формах по обычному без всяких паттернов. Я хочу попрактиковаться в создании приложений на WPF с использованием MVVM, поэтому и решил делать не на winforms.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
18.04.2022, 18:08  [ТС]
Цитата Сообщение от Bellatrix27 Посмотреть сообщение
Я хочу попрактиковаться в создании приложений на WPF с использованием MVVM, поэтому и решил делать не на winforms.
1) Начинаете с БД и Репозитория. Проще всего использовать SQLite и EF. Создаёте в EF с Code First.

2) Создаёте Модель со всеми нужными вам методами: Авторизация, получение/создание/изменение теста/вопроса.

3) На этом этапе у вас уже будут все типы которые нуждаются в представлении, поэтому можете приступать к созданию страниц Представлений и интерфейсоd VM для них.

4) Создаёте навигатор для переключения страниц. Подключаете его к окну. Задаёте в нём связи между состоянием VM (пока через интерфейс) и выводимой страницей.

5) Реализуете все интерфейсы в VM/ Пока только с данными времени разработки. Отлаживаете на них Навигатор и страницы.

6) Реализуете в VM логику работы с Моделью.


Вот примерно такая общая последовательность создание приложения.
1
0 / 0 / 0
Регистрация: 05.05.2020
Сообщений: 35
18.04.2022, 21:41
Цитата Сообщение от Элд Хасп Посмотреть сообщение
4) Создаёте навигатор для переключения страниц. Подключаете его к окну. Задаёте в нём связи между состоянием VM (пока через интерфейс) и выводимой страницей.
Подойдёт ли в качестве навигатора подобная реализация?
Пункт 6. Простой навигатор через ViewModel
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
18.04.2022, 22:07  [ТС]
Цитата Сообщение от Bellatrix27 Посмотреть сообщение
Подойдёт ли в качестве навигатора подобная реализация?
Ну, если его несколько изменить....
Вам скорее нужна навигация через состояние VM.
Авторизация, тестирование, редактирование - это всё разные состояния Модели.
В зависимости от этих состояний будет меняться Бизнес Логика Модели.
Это состояние будет отражаться в каком-то свойстве VM.
И в качестве навигатора вполне хватит использования какого-го конвертера или селектора Шаблонов.

Добавлено через 6 минут
Bellatrix27, один из вариантов это сделать как в этой теме через переключения Контента в основной VN - в данном случае она и выполняет роль навигатора.
1
0 / 0 / 0
Регистрация: 05.05.2020
Сообщений: 35
18.04.2022, 22:30
Благодарю за разъяснения
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
18.04.2022, 22:30

WPF команды и MVVM. Часть 1. [WPF, Элд Хасп]
Тема из цикла https://www.cyberforum.ru/wpf-silverlight/thread2384523.html Для использования и создания WPF команд в Net предусмотрен...

WPF конвертеры [Элд Хасп]
Тема из цикла https://www.cyberforum.ru/wpf-silverlight/thread2384523.html View получает данные от ViewModel, но часто бывают случаи...

INPC (INotifyPropertyChanged) и получение данных из Модели [WPF, Элд Хасп]
Тема из цикла https://www.cyberforum.ru/wpf-silverlight/thread2384523.html MVVM состоит из трёх раздельных частей. &quot;Знания&quot;...

Готовые решения, примеры и рекомендации начинающим на WPF [Элд Хасп]
В этой теме перечень полезных тем для начинающих. Обсуждение введите в самих темах. Для включения темы в этот перечень - напишите...

Создания приложения для тестирования с заполнением тестов в БД
Перенесено из темы https://www.cyberforum.ru/wpf-silverlight/thread2471200.html Элд Хасп, Добрый вечер. Подскажите как вы реализовали,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
25
Ответ Создать тему
Новые блоги и статьи
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru