添加消息通知功能,使用Handy Control的Grow来实现的

This commit is contained in:
2025-06-14 19:34:12 +08:00
parent 1fbf8b8fa6
commit 5dfce624c4
10 changed files with 195 additions and 81 deletions

View File

@@ -11,6 +11,9 @@
<ui:ThemeResources/> <ui:ThemeResources/>
<ui:XamlControlsResources/> <ui:XamlControlsResources/>
<ResourceDictionary Source="Resources/DevicesItemTemplateDictionary.xaml" /> <ResourceDictionary Source="Resources/DevicesItemTemplateDictionary.xaml" />
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -24,6 +24,7 @@ namespace PMSWPF
container.AddSingleton<NavgatorServices>(); container.AddSingleton<NavgatorServices>();
container.AddSingleton<DevicesRepositories>(); container.AddSingleton<DevicesRepositories>();
container.AddSingleton<IDeviceDialogService, DeviceDialogService>(); container.AddSingleton<IDeviceDialogService, DeviceDialogService>();
container.AddSingleton<INotificationService, GrowlNotificationService>();
container.AddSingleton<MainViewModel>(); container.AddSingleton<MainViewModel>();
container.AddSingleton<HomeViewModel>(); container.AddSingleton<HomeViewModel>();
container.AddSingleton<DevicesViewModel>(); container.AddSingleton<DevicesViewModel>();

13
Enums/NotificationType.cs Normal file
View File

@@ -0,0 +1,13 @@
namespace PMSWPF.Enums;
public enum NotificationType
{
Info,
Warning,
Error,
Fatal,
Success,
Clear,
Ask
}

10
Models/Notification.cs Normal file
View File

@@ -0,0 +1,10 @@
using PMSWPF.Enums;
namespace PMSWPF.Models;
public class Notification
{
public string Message { get; set; }
public NotificationType Type { get; set; }
public bool IsGlobal { get; set; }
}

View File

@@ -0,0 +1,77 @@
using HandyControl.Controls;
using PMSWPF.Enums;
using Notification = PMSWPF.Models.Notification;
namespace PMSWPF.Services;
public class GrowlNotificationService : INotificationService
{
public void Show(Notification notification)
{
if (notification == null )
{
return;
}
if (notification.IsGlobal)
{
switch (notification.Type)
{
case NotificationType.Info:
Growl.InfoGlobal(notification.Message);
break;
case NotificationType.Error:
Growl.ErrorGlobal(notification.Message);
break;
case NotificationType.Warning:
Growl.WarningGlobal(notification.Message);
break;
case NotificationType.Success:
Growl.SuccessGlobal(notification.Message);
break;
case NotificationType.Fatal:
Growl.FatalGlobal(notification.Message);
break;
case NotificationType.Clear:
Growl.ClearGlobal();
break;
default:
Growl.InfoGlobal(notification.Message);
break;
}
}
else
{
switch (notification.Type)
{
case NotificationType.Info:
Growl.Info(notification.Message);
break;
case NotificationType.Error:
Growl.Error(notification.Message);
break;
case NotificationType.Warning:
Growl.Warning(notification.Message);
break;
case NotificationType.Success:
Growl.Success(notification.Message);
break;
case NotificationType.Fatal:
Growl.Fatal(notification.Message);
break;
case NotificationType.Clear:
Growl.Clear();
break;
default:
Growl.Info(notification.Message);
break;
}
}
}
public void Show(string message, NotificationType type=NotificationType.Info,bool IsGlobal=true)
{
Show(new Notification(){Message = message,Type = type,IsGlobal = IsGlobal});
}
}

View File

@@ -0,0 +1,10 @@
using PMSWPF.Enums;
using PMSWPF.Models;
namespace PMSWPF.Services;
public interface INotificationService
{
void Show(Notification notification);
void Show(string message, NotificationType type, bool IsGlobal);
}

View File

@@ -1,9 +1,11 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using HandyControl.Controls;
using HandyControl.Data;
using PMSWPF.Data.Entities; using PMSWPF.Data.Entities;
using PMSWPF.Data.Repositories; using PMSWPF.Data.Repositories;
using PMSWPF.Enums;
using PMSWPF.Excptions; using PMSWPF.Excptions;
using PMSWPF.Extensions; using PMSWPF.Extensions;
using PMSWPF.Helper; using PMSWPF.Helper;
@@ -11,6 +13,8 @@ using PMSWPF.Models;
using PMSWPF.Services; using PMSWPF.Services;
using PMSWPF.ViewModels.Dialogs; using PMSWPF.ViewModels.Dialogs;
using PMSWPF.Views.Dialogs; using PMSWPF.Views.Dialogs;
using MessageBox = System.Windows.MessageBox;
using Notification = PMSWPF.Models.Notification;
namespace PMSWPF.ViewModels; namespace PMSWPF.ViewModels;
@@ -18,59 +22,74 @@ public partial class DevicesViewModel : ViewModelBase
{ {
private readonly IDeviceDialogService _deviceDialogService; private readonly IDeviceDialogService _deviceDialogService;
private readonly DevicesRepositories _devicesRepositories; private readonly DevicesRepositories _devicesRepositories;
[ObservableProperty] private readonly INotificationService _notificationService;
private ObservableCollection<Device> _devices; [ObservableProperty] private ObservableCollection<Device> _devices = new ();
public DevicesViewModel(IDeviceDialogService deviceDialogService,DevicesRepositories devicesRepositories)
public DevicesViewModel(IDeviceDialogService deviceDialogService, DevicesRepositories devicesRepositories,INotificationService notificationService)
{ {
_deviceDialogService = deviceDialogService; _deviceDialogService = deviceDialogService;
_devicesRepositories = devicesRepositories; _devicesRepositories = devicesRepositories;
_devices = new ObservableCollection<Device>(); _notificationService = notificationService;
} }
public async Task OnLoadedAsync() public async Task OnLoadedAsync()
{ {
var ds = await _devicesRepositories.GetAll(); var ds = await _devicesRepositories.GetAll();
_devices.Clear();
foreach (var dbDevice in ds) foreach (var dbDevice in ds)
{ {
var deviceExist= _devices.FirstOrDefault(d => d.Id == dbDevice.Id); Device device = new Device();
if (deviceExist == null) dbDevice.CopyTo(device);
{ _devices.Add(device);
Device device = new Device();
dbDevice.CopyTo(device);
_devices.Add(device);
}
} }
} }
[RelayCommand]
public void Test()
{
// GrowlInfo info = new GrowlInfo();
// info.Message = "Hello";
// info.Type = InfoType.Error;
// info.ShowCloseButton = true;
_notificationService.Show( "Hello",NotificationType.Info,true);
// Growl.Error("Hello");
// Growl.Info("Hello");
// Growl.Success("Hello");
// Growl.WarningGlobal("Hello");
// Growl.SuccessGlobal("Hello");
// Growl.FatalGlobal("Hello");
// Growl.Ask("Hello", isConfirmed =>
// {
// Growl.Info(isConfirmed.ToString());
// return true;
// });
}
[RelayCommand] [RelayCommand]
public async void AddDevice() public async void AddDevice()
{ {
try try
{ {
Device device = await _deviceDialogService.ShowAddDeviceDialog();
Device device= await _deviceDialogService.ShowAddDeviceDialog(); if (device != null)
if (device != null) {
{ DbDevice dbDevice = new DbDevice();
DbDevice dbDevice = new DbDevice(); device.CopyTo<DbDevice>(dbDevice);
device.CopyTo<DbDevice>(dbDevice); var rowCount = await _devicesRepositories.Add(dbDevice);
var rowCount= await _devicesRepositories.Add(dbDevice); if (rowCount > 0)
if (rowCount>0) {
{ // MessageBox.Show("Device added successfully");
// MessageBox.Show("Device added successfully"); await OnLoadedAsync();
await OnLoadedAsync(); _notificationService.Show(new Notification(){Message = "Hello World!",Type = NotificationType.Success,IsGlobal = true});
} }
} }
} }
catch (DbExistException e) catch (DbExistException e)
{ {
Console.WriteLine(e); Console.WriteLine(e);
MessageBox.Show(e.Message); MessageBox.Show(e.Message);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -81,12 +100,6 @@ public partial class DevicesViewModel : ViewModelBase
public override void OnLoaded() public override void OnLoaded()
{ {
OnLoadedAsync().Await((e) => OnLoadedAsync().Await((e) => { _deviceDialogService.ShowMessageDialog("", e.Message); }, () => { });
{
_deviceDialogService.ShowMessageDialog("",e.Message);
}, () =>
{
});
} }
} }

View File

@@ -9,13 +9,18 @@
xmlns:dl="clr-namespace:PMSWPF.Views.Dialogs" xmlns:dl="clr-namespace:PMSWPF.Views.Dialogs"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:vm="clr-namespace:PMSWPF.ViewModels" xmlns:vm="clr-namespace:PMSWPF.ViewModels"
xmlns:hc="https://handyorg.github.io/handycontrol"
d:DataContext="{d:DesignInstance vm:DevicesViewModel}" d:DataContext="{d:DesignInstance vm:DevicesViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"> d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<StackPanel Margin="10 5" Orientation="Horizontal"> <StackPanel ZIndex="1" >
<StackPanel Margin="10 5" Orientation="Horizontal">
<Button Margin="5" Command="{Binding AddDeviceCommand}" Content="添加"/> <Button Margin="5" Command="{Binding AddDeviceCommand}" Content="添加"/>
<Button Margin="5" Command="{Binding TestCommand}" Content="测试通知"/>
</StackPanel> </StackPanel>
<ui:GridView x:Name="BasicGridView" <ui:GridView x:Name="BasicGridView"
Margin="10" Margin="10"
IsItemClickEnabled="True" IsItemClickEnabled="True"

View File

@@ -10,6 +10,7 @@ public partial class DevicesView : UserControl
public DevicesView() public DevicesView()
{ {
InitializeComponent(); InitializeComponent();
} }
private void BasicGridView_ItemClick(object sender, ItemClickEventArgs e) private void BasicGridView_ItemClick(object sender, ItemClickEventArgs e)

View File

@@ -9,6 +9,7 @@
xmlns:local="clr-namespace:PMSWPF.Views" xmlns:local="clr-namespace:PMSWPF.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:PMSWPF.ViewModels" xmlns:vm="clr-namespace:PMSWPF.ViewModels"
xmlns:hc="https://handyorg.github.io/handycontrol"
Title="MainView" Title="MainView"
Width="800" Width="800"
Height="600" Height="600"
@@ -51,35 +52,9 @@
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Switch}" /> <ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Switch}" />
</ui:NavigationViewItem.Icon> </ui:NavigationViewItem.Icon>
</ui:NavigationViewItem> </ui:NavigationViewItem>
<!-- <ui:NavigationViewItemHeader Content="Actions" /> -->
<!-- <ui:NavigationViewItem -->
<!-- x:Name="SamplePage2Item" -->
<!-- Content="Menu Item2" -->
<!-- SelectsOnInvoked="True" -->
<!-- Tag="SamplePage2"> -->
<!-- <ui:NavigationViewItem.Icon> -->
<!-- <ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Save}" /> -->
<!-- </ui:NavigationViewItem.Icon> -->
<!-- </ui:NavigationViewItem> -->
<!-- <ui:NavigationViewItem -->
<!-- x:Name="SamplePage3Item" -->
<!-- Content="Menu Item3" -->
<!-- Tag="SamplePage3"> -->
<!-- <ui:NavigationViewItem.Icon> -->
<!-- <ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Refresh}" /> -->
<!-- </ui:NavigationViewItem.Icon> -->
<!-- </ui:NavigationViewItem> -->
</ui:NavigationView.MenuItems> </ui:NavigationView.MenuItems>
<!-- <ui:NavigationView.PaneCustomContent> -->
<!-- <ui:HyperlinkButton -->
<!-- x:Name="PaneHyperlink" -->
<!-- Margin="12,0" -->
<!-- Content="More info" -->
<!-- Visibility="Collapsed" /> -->
<!-- </ui:NavigationView.PaneCustomContent> -->
<ui:NavigationView.AutoSuggestBox> <ui:NavigationView.AutoSuggestBox>
<ui:AutoSuggestBox AutomationProperties.Name="Search"> <ui:AutoSuggestBox AutomationProperties.Name="Search">
<ui:AutoSuggestBox.QueryIcon> <ui:AutoSuggestBox.QueryIcon>
@@ -94,7 +69,6 @@
<StackPanel <StackPanel
x:Name="FooterStackPanel" x:Name="FooterStackPanel"
Margin="0" Margin="0"
Orientation="Vertical" Orientation="Vertical"
Visibility="Visible"> Visibility="Visible">
<ui:NavigationViewItem Content="设置"> <ui:NavigationViewItem Content="设置">
@@ -109,20 +83,27 @@
</ui:NavigationViewItem> </ui:NavigationViewItem>
</StackPanel> </StackPanel>
</ui:NavigationView.PaneFooter> </ui:NavigationView.PaneFooter>
<Grid>
<ContentControl Content="{Binding CurrentViewModel}">
<ContentControl.Resources> <ContentControl Content="{Binding CurrentViewModel}">
<DataTemplate DataType="{x:Type vm:HomeViewModel}"> <ContentControl.Resources>
<local:HomeView/> <DataTemplate DataType="{x:Type vm:HomeViewModel}">
</DataTemplate> <local:HomeView/>
<DataTemplate DataType="{x:Type vm:DevicesViewModel}"> </DataTemplate>
<local:DevicesView/> <DataTemplate DataType="{x:Type vm:DevicesViewModel}">
</DataTemplate> <local:DevicesView/>
<DataTemplate DataType="{x:Type vm:DataTransformViewModel}"> </DataTemplate>
<local:DataTransformView/> <DataTemplate DataType="{x:Type vm:DataTransformViewModel}">
</DataTemplate> <local:DataTransformView/>
</ContentControl.Resources> </DataTemplate>
</ContentControl> </ContentControl.Resources>
</ContentControl>
<ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalAlignment="Right">
<StackPanel hc:Growl.GrowlParent="True" VerticalAlignment="Top" Margin="0,10,10,10"/>
</ScrollViewer>
</Grid>
</ui:NavigationView> </ui:NavigationView>
</Grid> </Grid>
</Window> </Window>