Для моей программы на WPF мне потребовалось добавить системные Toast-уведомления в Windows 10+. В принципе для C# есть официальный мануал для подобных уведомлений: Send a local toast notification from a C# app. Проблема в том, что для этого необходимо, чтобы проект был UWP, но мне он не подходит, т.к. для моего проекта нужны права администратора, чего нет в UWP (к тому же какое-то время ходят слухи о закрытии Windows Store и соответственно прекращении поддержки UWP). Может что-то и получилось бы с WinUI 3, но вроде пока здесь тоже возникают какие-то проблемы с повышением привилегий…
Учитывая всё вышесказанное, продолжу использовать WPF.
Сначала я решил подключить NuGet пакет Notifications.Wpf, но в итоге оказалось, что во-первых проект необоснованно сложный (мне в приложении нужно вывести лишь пару уведомлений), а во вторых видео-инструкция к нему обрывается на середине, так что даже просто разобраться в коде уже проблема.
Попробую показывать уведомления через вызов Windows 10 API. Базовую статью я нашёл в этом блоге. Судя по доменному имени, это официальный блог Microsoft, однако качество самого блога удручает — взять хотя бы разметку блоков с кодом. Ладно, попробую так разобраться…
Старая версия
1. Перед тем, как создавать проект, нужно добавить новые компоненты в Visual Studio, если такие пока не установлены:
▶ ▶
2. Через меню добавим ссылку на Windows.winmd:
] ▶ ▶
"C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.22000.0\Windows.winmd"
3. Установим WindowsRuntime
▶ ▶
NuGet\Install-Package System.Runtime.WindowsRuntime
4. Дополнительно нужно установить UwpDesktop:
NuGet\Install-Package UwpDesktop
Если сейчас всё оставить как есть, то при запуске получим ошибку
Чтобы её избежать, переходим к п.5.
5. Добавим ещё один компонент:
dotnet add package Microsoft.Windows.CsWinRT
Всё равно я получал кучу ошибок ещё на этапе проверки синтаксиса, например:
The type forwarder for type ‘Windows.Data.Xml.Dom.XmlDocument’ in assembly ‘Windows’ causes a cycle at DuckDuckGo
CS0234 The type or namespace name ‘System’ does not exist in the namespace ‘Windows’ (are you missing an assembly reference?) — Google Search
CS0234 The type or namespace name ‘Devices’ does not exist in the namespace ‘Windows’ (are you missing an assembly reference?) at DuckDuckGo
Рабочая версия GeoLocation Demo App
Я нашёл видео-демонстрацию возможностей WinRT как раз с таким примером, его и переделал.
GeoLocation Demo App:
Я немного переделал код из блога.
- Поскольку для доступа к WinRT API выставлены довольно жёсткие требования к версии ОС и .NET, то нам необходимо их выставить в свойствах проекта:
▶ ▶ ▶
: .NET 6.0
: Windows
: 10.0.17763.0
: Enable WPF for this project.GeolocationDemoApp.csproj<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> <RootNamespace>GeolocationDemoApp</RootNamespace> <Nullable>enable</Nullable> <UseWPF>True</UseWPF> </PropertyGroup> </Project>
Если этого не сделать, то компилятор выдаст ошибку:
Error CS0246 The type or namespace name ‘Windows’ could not be found (are you missing a using directive or an assembly reference?)
GeolocationDemoApp C:\Users\Denis\source\repos\GeolocationDemoApp\MainWindow.xaml.cs - В Дизайнере в окно программы добавим лишь одну кнопку:
MainWindow.xaml
<Window x:Class="GeolocationDemoApp.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:local="clr-namespace:GeolocationDemoApp" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Button Content="Button" Width="200" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click"/> <TextBlock x:Name="geoText" HorizontalAlignment="Center" Margin="0,291,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="TextBlock" VerticalAlignment="Top" Width="200" FontSize="24" Background="#FFEFEED6" /> </Grid> </Window>
- За логику кнопки будет отвечать следующий код:
MainWindow.xaml.cs
using System; using System.Windows; namespace GeolocationDemoApp { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void Button_Click(object sender, RoutedEventArgs e) { //throw new NotImplementedException(); var locator = new Windows.Devices.Geolocation.Geolocator(); var location = await locator.GetGeopositionAsync(); var position = location.Coordinate.Point.Position; var latlong = string.Format("lat:{0}, long:{1}", position.Latitude, position.Longitude); //var result = MessageBox.Show(latlong); geoText.Text = latlong; } } }
- Мы не включили в код обработку исключений. Поэтому, если на уровне системы запрещён доступ к местоположению, выскочит ошибка. А если запустить без отладки, никакого окошка не появится, поэтому нужно дать системе разрешение на доступ к местоположению:
▶ ▶ [ ] ▶ ▶ ▶ ▶
После этого нужно разрешить приложениям доступ к местоположению:
▶ ▶ [ ] ▶ ▶ ▶ - В результате, при нажатии на кнопку будут выведены долгота и широта текущего местоположения, переданного системой: