App.xaml
Здесь подключается глобальная тема Material Design, которая задаёт стиль всему приложению:
цвета, кнопки, поля ввода и элементы интерфейса.
BundledTheme задаёт цветовую схему, а ResourceDictionary подключает стандартные стили WPF-компонентов.
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
StartupUri="MainWindow.xaml">
MainWindow.xaml.cs
Этот код реализует обработчик кнопки загрузки файла.
Пользователь выбирает текстовый файл, данные считываются через DataTier, затем передаются в LogicTier для расчёта максимальной цены за/квадратный метр и средней цены квартир. Результаты выводятся в интерфейс WPF.
// Подключение базовых системных библиотек (.NET)
using System;
// Подключение WPF (окна, элементы управления)
using System.Windows;
// Подключение стандартного диалога открытия файла
using Microsoft.Win32;
// Подключение слоя данных (DataTier)
using DataTier;
// Подключение слоя бизнес-логики (LogicTier)
using LogicTier;
namespace PresentationTier
{
// Класс главного окна приложения (WPF Window)
public partial class MainWindow : Window
{
// Конструктор окна (вызывается при запуске приложения)
public MainWindow()
{
// Инициализация всех компонентов интерфейса из XAML
InitializeComponent();
}
// Обработчик нажатия кнопки "Загрузить файл"
private void Load_Click(object sender, RoutedEventArgs e)
{
// Оборачиваем код в try-catch для обработки ошибок
try
{
// Создаём стандартное окно выбора файла
var dialog = new OpenFileDialog();
// Показываем диалог пользователю
// Если пользователь нажал "Отмена" — выходим из метода
if (dialog.ShowDialog() != true)
return;
// Создаём объект репозитория (слой DataTier)
// Он отвечает за чтение данных из файла
var repo = new ФайлРепозиторий();
// Загружаем список объектов недвижимости из выбранного файла
var data = repo.Загрузить(dialog.FileName);
// Привязываем список к таблице DataGrid
// Теперь данные отображаются в интерфейсе
GridData.ItemsSource = data;
// Создаём объект бизнес-логики (слой LogicTier)
// Передаём ему загруженные данные
var logic = new Аналитика(data);
// Вычисляем объект с максимальной ценой за м²
var max = logic.МаксимальнаяЦенаЗаМ2();
// Вычисляем среднюю цену за м² только для квартир
var avg = logic.СредняяЦенаКвартир();
// Выводим результат максимального значения в интерфейс
MaxText.Text =
$"Максимальная цена за м²: {max.Тип} → {max.ЦенаЗаМ2:F2}";
// Выводим среднее значение для квартир
AvgText.Text =
$"Средняя цена квартир: {avg:F2}";
}
catch (Exception ex)
{
// Если произошла ошибка — показываем сообщение пользователю
MessageBox.Show(
"Ошибка: " + ex.Message, // текст ошибки
"Ошибка", // заголовок окна
MessageBoxButton.OK, // кнопка OK
MessageBoxImage.Error // иконка ошибки
);
}
}
}
}
MainWindow.xaml
Это главное окно приложения WPF. Оно состоит из трёх частей: кнопка загрузки файла, таблица для отображения данных и блок вывода результатов. Данные загружаются из файла, отображаются в DataGrid, а затем через бизнес-логику вычисляются аналитические показатели.
// Главное окно WPF приложения
Аналитика.cs
Этот класс относится к бизнес-логике приложения. Он получает список объектов недвижимости и выполняет расчёты: находит объект с максимальной ценой за квадратный метр и вычисляет среднюю цену квадратного метра только для квартир с использованием LINQ-запросов.
// Подключение коллекций (List)
using System.Collections.Generic;
// Подключение LINQ (Where, OrderByDescending, Average и т.д.)
using System.Linq;
// Подключение слоя данных (класс Недвижимость)
using DataTier;
namespace LogicTier
{
// Класс бизнес-логики (выполняет расчёты над данными)
public class Аналитика
{
// Поле для хранения списка объектов недвижимости
private List<Недвижимость> данные;
// Конструктор класса
// Вызывается при создании объекта Аналитика
public Аналитика(List<Недвижимость> items)
{
// Сохраняем переданный список в поле класса
данные = items;
}
// Метод: найти объект с максимальной ценой за м²
public Недвижимость МаксимальнаяЦенаЗаМ2()
{
// LINQ:
// OrderByDescending → сортировка по убыванию цены за м²
// First() → берём первый элемент (самый дорогой)
return данные.OrderByDescending(x => x.ЦенаЗаМ2).First();
}
// Метод: вычислить среднюю цену за м² только для квартир
public double СредняяЦенаКвартир()
{
return данные
// фильтрация: берём только объекты типа "Квартира"
.Where(x => x.Тип == "Квартира")
// вычисление среднего значения цены за м²
.Average(x => x.ЦенаЗаМ2);
}
}
}
ФайлРепозиторий.cs
Этот класс реализует слой доступа к данным. Он считывает текстовый файл, разбивает строки на части, преобразует их в объекты недвижимости и формирует список. При ошибках в данных программа не падает, а пропускает некорректные строки.
// Подключение базовых классов .NET (Exception, String и т.д.)
using System;
// Подключение коллекций (List)
using System.Collections.Generic;
// Подключение культуры (нужно для корректного парсинга чисел с точкой)
using System.Globalization;
// Подключение работы с файлами (File.ReadAllLines)
using System.IO;
namespace DataTier
{
// Класс отвечает за чтение данных из текстового файла
public class ФайлРепозиторий
{
// Метод загрузки данных из файла
public List<Недвижимость> Загрузить(string путь)
{
// Создаём список объектов недвижимости
var list = new List<Недвижимость>();
// Читаем все строки файла сразу в память
foreach (var line in File.ReadAllLines(путь))
{
// Если строка пустая или состоит только из пробелов — пропускаем её
if (string.IsNullOrWhiteSpace(line))
continue;
// Разбиваем строку по запятой
var parts = line.Split(',');
// Оборачиваем парсинг в try-catch,
// чтобы не падало приложение при ошибочных данных
try
{
// Создаём новый объект недвижимости и добавляем в список
list.Add(new Недвижимость
{
// Первый элемент — тип объекта (Квартира, Дом и т.д.)
Тип = parts[0].Trim(),
// Удаляем слово "комнаты" и преобразуем строку в число
Комнаты = int.Parse(
parts[1]
.Replace("комнаты", "")
.Trim()
),
// Удаляем "м2", приводим к формату double
// CultureInfo.InvariantCulture нужен для точки вместо запятой
Метраж = double.Parse(
parts[2]
.Replace("м2", "")
.Trim(),
CultureInfo.InvariantCulture
),
// Преобразуем стоимость в decimal
Стоимость = decimal.Parse(parts[3].Trim())
});
}
catch
{
// Если строка повреждена или неверный формат —
// просто пропускаем её и продолжаем работу
continue;
}
}
// Возвращаем полностью загруженный список объектов
return list;
}
}
}
ТоварНедвижимости.cs
Этот класс является моделью данных. Он описывает объект недвижимости с основными характеристиками: тип, количество комнат, площадь и стоимость. Также содержит вычисляемое свойство — цену за квадратный метр, которая рассчитывается автоматически на основе стоимости и площади.
// Объявление пространства имён слоя данных
// DataTier — отвечает за хранение и описание данных
namespace DataTier
{
// Класс, описывающий один объект недвижимости
public class Недвижимость
{
// Тип недвижимости (например: Квартира, Дом, Коттедж)
// string? означает, что значение может быть null (не задано)
public string? Тип { get; set; }
// Количество комнат в объекте недвижимости
public int Комнаты { get; set; }
// Площадь объекта в квадратных метрах
public double Метраж { get; set; }
// Общая стоимость объекта недвижимости
public decimal Стоимость { get; set; }
// Вычисляемое свойство (не хранится в памяти напрямую)
// рассчитывается каждый раз при обращении
public double ЦенаЗаМ2
{
get
{
// формула расчёта цены за квадратный метр:
// стоимость делим на площадь
// decimal приводится к double для удобства вывода
return (double)(Стоимость / (decimal)Метраж);
}
}
}
}