Guest

dobegexam

Jun 5th, 2026
9
0
Never
Not a member of GistPad yet? Sign Up, it unlocks many cool features!
None 62.25 KB | None | 0 0
  1. ================================================================================
  2. ПРОЕКТ: AvaloniaApplication1 (Магазин обуви Botinki)
  3. ================================================================================
  4.  
  5. --------------------------------------------------------------------------------
  6. ФАЙЛ: AvaloniaApplication1.csproj
  7. --------------------------------------------------------------------------------
  8.  
  9. <Project Sdk="Microsoft.NET.Sdk">
  10. <PropertyGroup>
  11. <OutputType>WinExe</OutputType>
  12. <TargetFramework>net10.0</TargetFramework>
  13. <Nullable>enable</Nullable>
  14. <ApplicationManifest>app.manifest</ApplicationManifest>
  15. <RootNamespace>AvaloniaApplication1</RootNamespace>
  16. </PropertyGroup>
  17.  
  18. <ItemGroup>
  19. <PackageReference Include="Avalonia" Version="11.3.11" />
  20. <PackageReference Include="Avalonia.Desktop" Version="11.3.11" />
  21. <PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.11" />
  22. <PackageReference Include="Npgsql" Version="8.0.5" />
  23. </ItemGroup>
  24.  
  25. <ItemGroup>
  26. <AvaloniaResource Include="Assets\**\*" />
  27. <None Include="Assets\**\*">
  28. <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  29. </None>
  30. </ItemGroup>
  31. </Project>
  32.  
  33. --------------------------------------------------------------------------------
  34. ФАЙЛ: Program.cs
  35. --------------------------------------------------------------------------------
  36.  
  37. using System;
  38. using Avalonia;
  39.  
  40. namespace AvaloniaApplication1;
  41.  
  42. internal static class Program
  43. {
  44. [STAThread]
  45. public static void Main(string[] args) => BuildAvaloniaApp()
  46. .StartWithClassicDesktopLifetime(args);
  47.  
  48. public static AppBuilder BuildAvaloniaApp()
  49. => AppBuilder.Configure<App>()
  50. .UsePlatformDetect()
  51. .LogToTrace();
  52. }
  53.  
  54. --------------------------------------------------------------------------------
  55. ФАЙЛ: App.axaml
  56. --------------------------------------------------------------------------------
  57.  
  58. <Application xmlns="https://github.com/avaloniaui";
  59. x:Class="AvaloniaApplication1.App"
  60. RequestedThemeVariant="Default">
  61. <Application.Resources>
  62. <Color x:Key="PrimaryBackgroundColor">#FFFFFF</Color>
  63. <Color x:Key="SecondaryBackgroundColor">#7FFF00</Color>
  64. <Color x:Key="AccentColor">#00FA9A</Color>
  65.  
  66. <SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="{DynamicResource PrimaryBackgroundColor}" />
  67. <SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="{DynamicResource SecondaryBackgroundColor}" />
  68. <SolidColorBrush x:Key="AccentBrush" Color="{DynamicResource AccentColor}" />
  69. </Application.Resources>
  70. <Application.Styles>
  71. <FluentTheme />
  72. <Style Selector="Window">
  73. <Setter Property="Background" Value="{DynamicResource PrimaryBackgroundBrush}" />
  74. </Style>
  75. <Style Selector="TextBox">
  76. <Setter Property="Background" Value="{DynamicResource PrimaryBackgroundBrush}" />
  77. <Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}" />
  78. </Style>
  79. <Style Selector="Button">
  80. <Setter Property="Background" Value="{DynamicResource SecondaryBackgroundBrush}" />
  81. <Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}" />
  82. <Setter Property="Foreground" Value="Black" />
  83. </Style>
  84. <Style Selector="Border.card">
  85. <Setter Property="Background" Value="{DynamicResource PrimaryBackgroundBrush}" />
  86. <Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}" />
  87. </Style>
  88. </Application.Styles>
  89. </Application>
  90.  
  91. --------------------------------------------------------------------------------
  92. ФАЙЛ: App.axaml.cs
  93. --------------------------------------------------------------------------------
  94.  
  95. using Avalonia;
  96. using Avalonia.Controls.ApplicationLifetimes;
  97. using Avalonia.Markup.Xaml;
  98. using AvaloniaApplication1.Views;
  99.  
  100. namespace AvaloniaApplication1;
  101.  
  102. public partial class App : Application
  103. {
  104. public override void Initialize()
  105. {
  106. AvaloniaXamlLoader.Load(this);
  107. }
  108.  
  109. public override void OnFrameworkInitializationCompleted()
  110. {
  111. if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
  112. desktop.MainWindow = new LoginWindow();
  113.  
  114. base.OnFrameworkInitializationCompleted();
  115. }
  116. }
  117.  
  118. --------------------------------------------------------------------------------
  119. ФАЙЛ: Models/User.cs
  120. --------------------------------------------------------------------------------
  121.  
  122. namespace AvaloniaApplication1.Models;
  123.  
  124. public sealed class User
  125. {
  126. public int Id { get; set; }
  127. public string Login { get; set; } = "";
  128. public string Password { get; set; } = "";
  129. public string Role { get; set; } = "";
  130. public string FullName { get; set; } = "";
  131. }
  132.  
  133. --------------------------------------------------------------------------------
  134. ФАЙЛ: Models/Product.cs
  135. --------------------------------------------------------------------------------
  136.  
  137. using System;
  138. using System.IO;
  139.  
  140. namespace AvaloniaApplication1.Models;
  141.  
  142. public sealed class Product
  143. {
  144. private static readonly string DefaultPhotoPath;
  145.  
  146. static Product()
  147. {
  148. // Find default photo in Assets
  149. var baseDir = AppContext.BaseDirectory;
  150. var candidates = new[]
  151. {
  152. Path.Combine(baseDir, "Assets", "Icon.png"),
  153. Path.Combine(baseDir, "Assets", "Icon.JPG"),
  154. Path.Combine(baseDir, "Assets", "Icon.ico"),
  155. Path.Combine(baseDir, "..", "..", "..", "Assets", "Icon.png"),
  156. Path.Combine(baseDir, "..", "..", "..", "Assets", "Icon.JPG"),
  157. Path.Combine(Environment.CurrentDirectory, "Assets", "Icon.png"),
  158. Path.Combine(Environment.CurrentDirectory, "Assets", "Icon.JPG"),
  159. };
  160.  
  161. DefaultPhotoPath = string.Empty;
  162. foreach (var candidate in candidates)
  163. {
  164. var fullPath = Path.GetFullPath(candidate);
  165. if (File.Exists(fullPath))
  166. {
  167. DefaultPhotoPath = fullPath;
  168. break;
  169. }
  170. }
  171. }
  172.  
  173. public int ProductId { get; set; }
  174. public string Article { get; set; } = "";
  175. public int CategoryId { get; set; }
  176. public int SupplierId { get; set; }
  177. public int TypeProductId { get; set; }
  178. public decimal Price { get; set; }
  179. public string Discount { get; set; } = "0";
  180. public string Description { get; set; } = "";
  181.  
  182. private string _photo = "";
  183. public string Photo
  184. {
  185. get => string.IsNullOrWhiteSpace(_photo) ? DefaultPhotoPath : _photo;
  186. set => _photo = value ?? "";
  187. }
  188.  
  189. public decimal FinalPrice
  190. {
  191. get
  192. {
  193. if (!decimal.TryParse(Discount.Replace("%", ""), out var discountValue))
  194. {
  195. discountValue = 0;
  196. }
  197.  
  198. return Price * (100m - discountValue) / 100m;
  199. }
  200. }
  201. }
  202.  
  203. --------------------------------------------------------------------------------
  204. ФАЙЛ: Models/Order.cs
  205. --------------------------------------------------------------------------------
  206.  
  207. namespace AvaloniaApplication1.Models;
  208.  
  209. public sealed class Order
  210. {
  211. public int OrderId { get; set; }
  212. public string OrderArticle { get; set; } = "";
  213. public string DateOrder { get; set; } = "";
  214. public string DateDelivery { get; set; } = "";
  215. public int PickUpPointId { get; set; }
  216. public string Code { get; set; } = "";
  217. public string StatusOrder { get; set; } = "Новый";
  218. public int UserId { get; set; }
  219. public decimal TotalSum { get; set; }
  220. }
  221.  
  222. --------------------------------------------------------------------------------
  223. ФАЙЛ: services/DbService.cs
  224. --------------------------------------------------------------------------------
  225.  
  226. using System;
  227. using System.Collections.Generic;
  228. using System.IO;
  229. using System.Linq;
  230. using AvaloniaApplication1.Models;
  231. using Npgsql;
  232.  
  233. namespace AvaloniaApplication1.Services;
  234.  
  235. public sealed class DbService
  236. {
  237. // Меняешь тут: свою БД, логин, пароль
  238. private readonly string _connectionString = "Host=localhost;Port=5432;Username=postgres;Password=123;Database=Botinki";
  239.  
  240. // ========== АВТОРИЗАЦИЯ ==========
  241. public User? Login(string login, string password)
  242. {
  243. using var conn = OpenConnection();
  244. using var cmd = new NpgsqlCommand(
  245. """
  246. SELECT u.user_id, u.login, u.password, COALESCE(r.name_role, 'Клиент') AS role_name,
  247. TRIM(COALESCE(u.name, '') || ' ' || COALESCE(u.second_name, '') || ' ' || COALESCE(u.patronymic, '')) AS full_name
  248. FROM users u
  249. LEFT JOIN roles r ON r.role_id = u.role_id
  250. WHERE u.login = @l AND u.password = @p
  251. """, conn);
  252.  
  253. cmd.Parameters.AddWithValue("l", login);
  254. cmd.Parameters.AddWithValue("p", password);
  255.  
  256. using var reader = cmd.ExecuteReader();
  257. if (reader.Read())
  258. {
  259. return new User
  260. {
  261. Id = reader.GetInt32(0),
  262. Login = reader.GetString(1),
  263. Password = reader.GetString(2),
  264. Role = NormalizeRole(reader.GetString(3)),
  265. FullName = reader.GetString(4)
  266. };
  267. }
  268. return null;
  269. }
  270.  
  271. // ========== ТОВАРЫ ==========
  272. public List<Product> GetProducts()
  273. {
  274. var list = new List<Product>();
  275. using var conn = OpenConnection();
  276. using var cmd = new NpgsqlCommand(
  277. """
  278. SELECT product_id, article, category_id, supplier_id, price, discount, description, photo
  279. FROM products
  280. ORDER BY product_id
  281. """, conn);
  282.  
  283. using var reader = cmd.ExecuteReader();
  284. while (reader.Read())
  285. {
  286. list.Add(new Product
  287. {
  288. ProductId = reader.GetInt32(0),
  289. Article = reader.GetString(1),
  290. CategoryId = reader.IsDBNull(2) ? 0 : reader.GetInt32(2),
  291. SupplierId = reader.IsDBNull(3) ? 0 : reader.GetInt32(3),
  292. TypeProductId = 0,
  293. Price = reader.IsDBNull(4) ? 0m : reader.GetDecimal(4),
  294. Discount = reader.IsDBNull(5) ? "0" : reader.GetString(5),
  295. Description = reader.IsDBNull(6) ? "" : reader.GetString(6),
  296. Photo = reader.IsDBNull(7) ? "" : ResolvePhotoPath(reader.GetString(7))
  297. });
  298. }
  299. return list;
  300. }
  301.  
  302. // ========== ПОИСК ФОТО ==========
  303. private static string ResolvePhotoPath(string photoValue)
  304. {
  305. if (string.IsNullOrWhiteSpace(photoValue)) return "";
  306. var value = photoValue.Trim();
  307.  
  308. if (Path.IsPathRooted(value) && File.Exists(value))
  309. return value;
  310.  
  311. var fileName = Path.GetFileNameWithoutExtension(value);
  312. var directories = new[]
  313. {
  314. Path.Combine(AppContext.BaseDirectory, "Assets"),
  315. Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "Assets")),
  316. Path.Combine(Environment.CurrentDirectory, "Assets")
  317. };
  318.  
  319. var extensions = new[] { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
  320.  
  321. foreach (var dir in directories)
  322. {
  323. var exact = Path.Combine(dir, value);
  324. if (File.Exists(exact)) return exact;
  325. foreach (var ext in extensions)
  326. {
  327. var candidate = Path.Combine(dir, fileName + ext);
  328. if (File.Exists(candidate)) return candidate;
  329. }
  330. }
  331. return "";
  332. }
  333.  
  334. // ========== ПОДКЛЮЧЕНИЕ ==========
  335. private NpgsqlConnection OpenConnection()
  336. {
  337. var conn = new NpgsqlConnection(_connectionString);
  338. conn.Open();
  339. return conn;
  340. }
  341.  
  342. // ========== НОРМАЛИЗАЦИЯ РОЛИ ==========
  343. private static string NormalizeRole(string role)
  344. {
  345. var r = role.Trim().ToLowerInvariant();
  346. return r switch
  347. {
  348. "администратор" => "admin",
  349. "админ" => "admin",
  350. "менеджер" => "manager",
  351. "manager" => "manager",
  352. "клиент" => "client",
  353. _ => "client"
  354. };
  355. }
  356. }
  357.  
  358. --------------------------------------------------------------------------------
  359. ФАЙЛ: Views/LoginWindow.axaml
  360. --------------------------------------------------------------------------------
  361.  
  362. x:Class="AvaloniaApplication1.Views.LoginWindow"
  363. Width="420" Height="380"
  364. Icon="/Assets/Icon.ico"
  365. Title="Авторизация"
  366. WindowStartupLocation="CenterScreen">
  367.  
  368. <Grid>
  369. <Border Background="{DynamicResource PrimaryBackgroundBrush}" CornerRadius="12" Margin="20">
  370. <StackPanel Margin="25" Spacing="14" VerticalAlignment="Center">
  371.  
  372. <!-- Logo -->
  373. <Border Background="{DynamicResource SecondaryBackgroundBrush}" CornerRadius="8" Padding="12" HorizontalAlignment="Center">
  374. <Image Source="/Assets/Icon.JPG" Width="64" Height="54" Stretch="Uniform"/>
  375. </Border>
  376.  
  377. <!-- Title -->
  378. <TextBlock Text="Вход в систему"
  379. FontSize="22"
  380. FontWeight="Bold"
  381. HorizontalAlignment="Center"
  382. Foreground="{DynamicResource AccentBrush}"/>
  383.  
  384. <!-- Login -->
  385. <TextBox x:Name="loginBox"
  386. Watermark="Логин"
  387. Height="36"
  388. CornerRadius="6"/>
  389.  
  390. <!-- Password -->
  391. <TextBox x:Name="passwordBox"
  392. PasswordChar="*"
  393. Watermark="Пароль"
  394. Height="36"
  395. CornerRadius="6"/>
  396.  
  397. <!-- Error -->
  398. <TextBlock x:Name="errorText"
  399. Foreground="#FF4444"
  400. TextWrapping="Wrap"
  401. FontSize="13"
  402. HorizontalAlignment="Center"/>
  403.  
  404. <!-- Login Button -->
  405. <Button Content="Войти"
  406. Click="Login_Click"
  407. HorizontalAlignment="Stretch"
  408. Height="38"
  409. CornerRadius="6"
  410. FontSize="15"
  411. FontWeight="Bold"
  412. IsDefault="True"/>
  413.  
  414. <!-- Guest Button -->
  415. <Button Content="Войти как гость"
  416. Click="Guest_Click"
  417. HorizontalAlignment="Stretch"
  418. Height="36"
  419. CornerRadius="6"
  420. FontSize="13"/>
  421.  
  422. </StackPanel>
  423. </Border>
  424. </Grid>
  425.  
  426. </Window>
  427.  
  428. --------------------------------------------------------------------------------
  429. ФАЙЛ: Views/LoginWindow.axaml.cs
  430. --------------------------------------------------------------------------------
  431.  
  432. using System;
  433. using Avalonia;
  434. using Avalonia.Controls;
  435. using Avalonia.Controls.ApplicationLifetimes;
  436. using Avalonia.Interactivity;
  437. using AvaloniaApplication1.Models;
  438. using AvaloniaApplication1.Services;
  439.  
  440. namespace AvaloniaApplication1.Views;
  441.  
  442. public partial class LoginWindow : Window
  443. {
  444. private readonly DbService _dbService = new();
  445.  
  446. public LoginWindow()
  447. {
  448. InitializeComponent();
  449. }
  450.  
  451. private void Login_Click(object? sender, RoutedEventArgs e)
  452. {
  453. errorText.Text = string.Empty;
  454.  
  455. var login = loginBox.Text?.Trim() ?? string.Empty;
  456. var password = passwordBox.Text?.Trim() ?? string.Empty;
  457.  
  458. if (string.IsNullOrWhiteSpace(login) || string.IsNullOrWhiteSpace(password))
  459. {
  460. errorText.Text = "Введите логин и пароль.";
  461. return;
  462. }
  463.  
  464. try
  465. {
  466. var user = _dbService.Login(login, password);
  467. if (user is null)
  468. {
  469. errorText.Text = "Неверный логин или пароль.";
  470. return;
  471. }
  472.  
  473. OpenRoleMenu(user);
  474. }
  475. catch (Exception ex)
  476. {
  477. errorText.Text = $"Ошибка подключения к БД: {ex.Message}";
  478. }
  479. }
  480.  
  481. private void Guest_Click(object? sender, RoutedEventArgs e)
  482. {
  483. errorText.Text = string.Empty;
  484. OpenRoleMenu(new User
  485. {
  486. Login = "guest",
  487. FullName = "Гость",
  488. Role = "client"
  489. });
  490. }
  491.  
  492. private void OpenRoleMenu(User user)
  493. {
  494. var roleWindow = new RoleWindow(user, _dbService);
  495. if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
  496. {
  497. desktop.MainWindow = roleWindow;
  498. }
  499.  
  500. roleWindow.Show();
  501. Close();
  502. }
  503. }
  504.  
  505. --------------------------------------------------------------------------------
  506. ФАЙЛ: Views/RoleWindow.axaml
  507. --------------------------------------------------------------------------------
  508.  
  509. x:Class="AvaloniaApplication1.Views.RoleWindow"
  510. Width="420" Height="280"
  511. Icon="/Assets/Icon.ico"
  512. Title="Главное меню"
  513. WindowStartupLocation="CenterScreen">
  514. <StackPanel Margin="25" Spacing="14" VerticalAlignment="Center">
  515.  
  516. <!-- Приветствие -->
  517. <TextBlock x:Name="helloText"
  518. FontSize="20"
  519. FontWeight="Bold"
  520. HorizontalAlignment="Center"/>
  521.  
  522. <!-- Твоя роль -->
  523. <TextBlock x:Name="roleText"
  524. FontSize="14"
  525. Foreground="#666"
  526. HorizontalAlignment="Center"/>
  527.  
  528. <!-- Просмотр товаров -->
  529. <Button Content="Просмотр товаров"
  530. Click="OpenProducts_Click"
  531. HorizontalAlignment="Stretch"
  532. Height="40"
  533. FontSize="15"/>
  534.  
  535. <!-- Выход -->
  536. <Button Content="Выход"
  537. Click="Exit_Click"
  538. HorizontalAlignment="Stretch"
  539. Height="36"
  540. FontSize="13"/>
  541.  
  542. </StackPanel>
  543. </Window>
  544.  
  545. --------------------------------------------------------------------------------
  546. ФАЙЛ: Views/RoleWindow.axaml.cs
  547. --------------------------------------------------------------------------------
  548.  
  549. using Avalonia;
  550. using Avalonia.Controls;
  551. using Avalonia.Controls.ApplicationLifetimes;
  552. using Avalonia.Interactivity;
  553. using AvaloniaApplication1.Models;
  554. using AvaloniaApplication1.Services;
  555.  
  556. namespace AvaloniaApplication1.Views;
  557.  
  558. public partial class RoleWindow : Window
  559. {
  560. private readonly User _user;
  561. private readonly DbService _dbService;
  562.  
  563. public RoleWindow(User user, DbService dbService)
  564. {
  565. _user = user;
  566. _dbService = dbService;
  567. InitializeComponent();
  568.  
  569. string name = _user.FullName.Trim();
  570. if (name == "") name = _user.Login;
  571. helloText.Text = $"Привет, {name}!";
  572. roleText.Text = $"Роль: {RoleName(_user.Role)}";
  573. }
  574.  
  575. private async void OpenProducts_Click(object? sender, RoutedEventArgs e)
  576. {
  577. await new ProductsWindow(_user, _dbService).ShowDialog(this);
  578. }
  579.  
  580. private void Exit_Click(object? sender, RoutedEventArgs e)
  581. {
  582. var login = new LoginWindow();
  583. if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
  584. desktop.MainWindow = login;
  585. login.Show();
  586. Close();
  587. }
  588.  
  589. private static string RoleName(string role) => role switch
  590. {
  591. "admin" => "Администратор",
  592. "manager" => "Менеджер",
  593. _ => "Клиент"
  594. };
  595. }
  596.  
  597. --------------------------------------------------------------------------------
  598. ФАЙЛ: Views/ProductsWindow.axaml
  599. --------------------------------------------------------------------------------
  600.  
  601. x:Class="AvaloniaApplication1.Views.ProductsWindow"
  602. Width="950" Height="650"
  603. Icon="/Assets/Icon.ico"
  604. Title="Товары"
  605. WindowStartupLocation="CenterOwner">
  606. <Grid RowDefinitions="Auto,*,Auto" Margin="12">
  607.  
  608. <!-- Шапка -->
  609. <Border Background="{DynamicResource SecondaryBackgroundBrush}" CornerRadius="8" Padding="12" Margin="0,0,0,10">
  610. <TextBlock x:Name="titleText" FontSize="20" FontWeight="Bold" HorizontalAlignment="Center"/>
  611. </Border>
  612.  
  613. <!-- Карточки товаров -->
  614. <ScrollViewer Grid.Row="1">
  615. <ItemsControl x:Name="productsControl">
  616. <ItemsControl.ItemsPanel>
  617. <ItemsPanelTemplate>
  618. <WrapPanel Orientation="Horizontal"/>
  619. </ItemsPanelTemplate>
  620. </ItemsControl.ItemsPanel>
  621. <ItemsControl.ItemTemplate>
  622. <DataTemplate>
  623. <Border Background="{DynamicResource PrimaryBackgroundBrush}"
  624. BorderBrush="{DynamicResource AccentBrush}"
  625. BorderThickness="1"
  626. CornerRadius="8"
  627. Width="200"
  628. Margin="6"
  629. Padding="8">
  630. <StackPanel Spacing="4">
  631. <!-- Фото -->
  632. <Border CornerRadius="6" Background="#F0F0F0" Height="120" HorizontalAlignment="Center" Width="120">
  633. <Image Source="{Binding Photo}" Width="110" Height="110" Stretch="Uniform"
  634. HorizontalAlignment="Center" VerticalAlignment="Center"/>
  635. </Border>
  636. <!-- Артикул -->
  637. <TextBlock Text="{Binding Article, StringFormat='Артикул: {0}'}" FontWeight="Bold" FontSize="12"/>
  638. <!-- Описание -->
  639. <TextBlock Text="{Binding Description}" TextWrapping="Wrap" FontSize="11" Foreground="#666" MaxHeight="40"/>
  640. <Separator/>
  641. <!-- Цена -->
  642. <TextBlock Text="{Binding Price, StringFormat='Цена: {0:F2} ₽'}" FontSize="12"/>
  643. <!-- Скидка -->
  644. <TextBlock Text="{Binding Discount, StringFormat='Скидка: {0}%'}" Foreground="#FF4444" FontWeight="Bold" FontSize="11"/>
  645. <!-- Итог -->
  646. <TextBlock Text="{Binding FinalPrice, StringFormat='Итог: {0:F2} ₽'}" FontWeight="Bold" FontSize="13"
  647. Foreground="{DynamicResource AccentBrush}"/>
  648. </StackPanel>
  649. </Border>
  650. </DataTemplate>
  651. </ItemsControl.ItemTemplate>
  652. </ItemsControl>
  653. </ScrollViewer>
  654.  
  655. <!-- Кнопка назад -->
  656. <Button Grid.Row="2" Content="Назад" Click="Back_Click" HorizontalAlignment="Left" Margin="0,10,0,0"/>
  657.  
  658. </Grid>
  659. </Window>
  660.  
  661. --------------------------------------------------------------------------------
  662. ФАЙЛ: Views/ProductsWindow.axaml.cs
  663. --------------------------------------------------------------------------------
  664.  
  665. using System;
  666. using System.Collections.Generic;
  667. using Avalonia.Controls;
  668. using Avalonia.Interactivity;
  669. using AvaloniaApplication1.Models;
  670. using AvaloniaApplication1.Services;
  671.  
  672. namespace AvaloniaApplication1.Views;
  673.  
  674. public partial class ProductsWindow : Window
  675. {
  676. private readonly User _user;
  677. private readonly DbService _dbService;
  678.  
  679. public ProductsWindow(User user, DbService dbService)
  680. {
  681. _user = user;
  682. _dbService = dbService;
  683. InitializeComponent();
  684.  
  685. titleText.Text = $"Товары ({RoleTitle(_user.Role)})";
  686. LoadProducts();
  687. }
  688.  
  689. private void LoadProducts()
  690. {
  691. try
  692. {
  693. var products = _dbService.GetProducts();
  694. productsControl.ItemsSource = products;
  695. }
  696. catch (Exception ex)
  697. {
  698. ShowError(ex.Message);
  699. }
  700. }
  701.  
  702. private void Back_Click(object? sender, RoutedEventArgs e)
  703. {
  704. Close();
  705. }
  706.  
  707. private async void ShowError(string message)
  708. {
  709. var dialog = new Window
  710. {
  711. Width = 400, Height = 150, Title = "Ошибка",
  712. Content = new StackPanel
  713. {
  714. Margin = new Avalonia.Thickness(16),
  715. Spacing = 12,
  716. Children =
  717. {
  718. new TextBlock { Text = message, TextWrapping = Avalonia.Media.TextWrapping.Wrap },
  719. new Button { Content = "OK", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Right }
  720. }
  721. }
  722. };
  723. ((Button)((StackPanel)dialog.Content).Children[1]).Click += (_, _) => dialog.Close();
  724. await dialog.ShowDialog(this);
  725. }
  726.  
  727. private static string RoleTitle(string role) => role switch
  728. {
  729. "admin" => "админ",
  730. "manager" => "менеджер",
  731. _ => "клиент"
  732. };
  733. }
  734.  
  735. ================================================================================
  736. КОНЕЦ ВСЕХ ФАЙЛОВ
  737. ================================================================================
RAW Paste Data Copied