This commit is contained in:
Курнат Андрей
2026-04-01 20:48:48 +03:00
commit a62252a181
8 changed files with 318 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.vs/
**/bin/
**/obj/

3
CLITPdfReader.slnx Normal file
View File

@@ -0,0 +1,3 @@
<Solution>
<Project Path="CLITPdfReader/CLITPdfReader.csproj" />
</Solution>

7
CLITPdfReader/App.xaml Normal file
View File

@@ -0,0 +1,7 @@
<Application x:Class="CLITPdfReader.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
</Application.Resources>
</Application>

22
CLITPdfReader/App.xaml.cs Normal file
View File

@@ -0,0 +1,22 @@
using System.IO;
using System.Windows;
namespace CLITPdfReader;
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
string? initialPdfPath = null;
if (e.Args.Length > 0 && File.Exists(e.Args[0]))
{
initialPdfPath = e.Args[0];
}
MainWindow = new MainWindow(initialPdfPath);
MainWindow.Show();
}
}

View File

@@ -0,0 +1,10 @@
using System.Windows;
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3856.49" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,78 @@
<Window x:Class="CLITPdfReader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
mc:Ignorable="d"
Title="CLIT PDF Reader"
Width="1200"
Height="800"
MinWidth="760"
MinHeight="520"
Loaded="Window_Loaded"
AllowDrop="True"
DragOver="Window_DragOver"
Drop="Window_Drop">
<DockPanel>
<Border DockPanel.Dock="Top"
Background="#FFF4F4F5"
BorderBrush="#FFE2E8F0"
BorderThickness="0,0,0,1">
<ToolBarTray>
<ToolBar FontSize="14"
Padding="6,2"
MinHeight="34">
<Button Command="ApplicationCommands.Open"
Padding="10,3"
Margin="0,0,8,0">Открыть PDF</Button>
<Button Command="ApplicationCommands.Print"
Padding="10,3"
Margin="0,0,16,0">Печать</Button>
<Separator />
<TextBlock VerticalAlignment="Center"
FontWeight="SemiBold"
Text="Файл:"
Margin="12,0,8,0" />
<TextBlock x:Name="CurrentFileTextBlock"
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis"
Width="760"
Foreground="#FF334155"
Text="PDF не открыт" />
</ToolBar>
</ToolBarTray>
</Border>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem>
<TextBlock x:Name="StatusTextBlock" Text="Готово к открытию PDF." />
</StatusBarItem>
</StatusBar>
<Grid Background="#FFF8FAFC">
<wv2:WebView2 x:Name="PdfView" />
<Border x:Name="PlaceholderPanel"
Background="#FFF8FAFC"
Visibility="Visible">
<StackPanel MaxWidth="520"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock x:Name="PlaceholderTitleTextBlock"
Text="Откройте PDF-файл"
FontSize="28"
FontWeight="SemiBold"
HorizontalAlignment="Center"
Margin="0,0,0,12" />
<TextBlock x:Name="PlaceholderDescriptionTextBlock"
Text="Используйте кнопку «Открыть PDF», горячую клавишу Ctrl+O или просто перетащите файл в окно."
TextAlignment="Center"
Foreground="#FF475569"
FontSize="15"
TextWrapping="Wrap" />
</StackPanel>
</Border>
</Grid>
</DockPanel>
</Window>

View File

@@ -0,0 +1,180 @@
using System.IO;
using System.Windows;
using System.Windows.Input;
using Microsoft.Web.WebView2.Core;
using Microsoft.Win32;
namespace CLITPdfReader;
public partial class MainWindow : Window
{
private const string AppTitle = "CLIT PDF Reader";
private readonly string? _initialPdfPath;
private bool _isBrowserReady;
private string? _currentPdfPath;
public MainWindow(string? initialPdfPath = null)
{
_initialPdfPath = initialPdfPath;
InitializeComponent();
CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, OpenCommand_Executed));
CommandBindings.Add(new CommandBinding(ApplicationCommands.Print, PrintCommand_Executed, PrintCommand_CanExecute));
InputBindings.Add(new KeyBinding(ApplicationCommands.Open, new KeyGesture(Key.O, ModifierKeys.Control)));
InputBindings.Add(new KeyBinding(ApplicationCommands.Print, new KeyGesture(Key.P, ModifierKeys.Control)));
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
await EnsureBrowserReadyAsync();
if (_isBrowserReady && !string.IsNullOrWhiteSpace(_initialPdfPath))
{
OpenPdf(_initialPdfPath);
}
}
private async Task<bool> EnsureBrowserReadyAsync()
{
if (_isBrowserReady)
{
return true;
}
try
{
await PdfView.EnsureCoreWebView2Async();
PdfView.CoreWebView2.Settings.HiddenPdfToolbarItems = CoreWebView2PdfToolbarItems.None;
_isBrowserReady = true;
UpdateCommandState();
return true;
}
catch (WebView2RuntimeNotFoundException)
{
ShowPlaceholder(
"WebView2 Runtime не найден",
"Установите Microsoft Edge WebView2 Runtime, после чего приложение сможет отображать PDF."
);
StatusTextBlock.Text = "Не найден Microsoft Edge WebView2 Runtime.";
return false;
}
catch (Exception ex)
{
ShowPlaceholder(
"Не удалось инициализировать просмотр",
ex.Message
);
StatusTextBlock.Text = "Ошибка инициализации WebView2.";
return false;
}
}
private async void OpenCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (!await EnsureBrowserReadyAsync())
{
return;
}
var openFileDialog = new OpenFileDialog
{
Title = "Выберите PDF-файл",
Filter = "PDF files (*.pdf)|*.pdf|All files (*.*)|*.*",
Multiselect = false
};
if (openFileDialog.ShowDialog(this) == true)
{
OpenPdf(openFileDialog.FileName);
}
}
private void PrintCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = _isBrowserReady && !string.IsNullOrWhiteSpace(_currentPdfPath);
}
private void PrintCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (!_isBrowserReady || PdfView.CoreWebView2 is null)
{
return;
}
PdfView.CoreWebView2.ShowPrintUI(CoreWebView2PrintDialogKind.Browser);
}
private void Window_DragOver(object sender, DragEventArgs e)
{
e.Effects = HasSinglePdfFile(e.Data) ? DragDropEffects.Copy : DragDropEffects.None;
e.Handled = true;
}
private async void Window_Drop(object sender, DragEventArgs e)
{
if (!HasSinglePdfFile(e.Data))
{
StatusTextBlock.Text = "Поддерживаются только PDF-файлы.";
return;
}
if (!await EnsureBrowserReadyAsync())
{
return;
}
var droppedFiles = e.Data.GetData(DataFormats.FileDrop) as string[];
if (droppedFiles is { Length: 1 })
{
OpenPdf(droppedFiles[0]);
}
}
private static bool HasSinglePdfFile(IDataObject dataObject)
{
if (!dataObject.GetDataPresent(DataFormats.FileDrop))
{
return false;
}
var files = dataObject.GetData(DataFormats.FileDrop) as string[];
return files is { Length: 1 } &&
File.Exists(files[0]) &&
string.Equals(Path.GetExtension(files[0]), ".pdf", StringComparison.OrdinalIgnoreCase);
}
private void OpenPdf(string pdfPath)
{
if (!File.Exists(pdfPath))
{
ShowPlaceholder("Файл не найден", pdfPath);
StatusTextBlock.Text = "Не удалось открыть файл.";
return;
}
_currentPdfPath = pdfPath;
PdfView.CoreWebView2.Navigate(new Uri(pdfPath).AbsoluteUri);
PlaceholderPanel.Visibility = Visibility.Collapsed;
CurrentFileTextBlock.Text = pdfPath;
Title = $"{Path.GetFileName(pdfPath)} - {AppTitle}";
StatusTextBlock.Text = "PDF открыт. Для печати нажмите Ctrl+P.";
UpdateCommandState();
}
private void ShowPlaceholder(string title, string description)
{
PlaceholderTitleTextBlock.Text = title;
PlaceholderDescriptionTextBlock.Text = description;
PlaceholderPanel.Visibility = Visibility.Visible;
CurrentFileTextBlock.Text = "PDF не открыт";
Title = AppTitle;
_currentPdfPath = null;
UpdateCommandState();
}
private void UpdateCommandState()
{
CommandManager.InvalidateRequerySuggested();
}
}