首页 > 其他分享 >WPF消息提示

WPF消息提示

时间:2023-08-03 18:02:13浏览次数:28  
标签:messageViewModel 提示 MessageHelper MessageType private 消息 WPF public

WPF消息提示

使用.net6.0

使用的NuGet包

MaterialDesignThemes:4.9.0
Prism.DryIoc:8.1.97

我们要做一个类似Element Plus或者Ant DesignMessage,作为消息提示这样的交互比较友好,老是用MessageBox也挺难受,先不管动画效果吧

分析

这种消息提示在应用程序中是个有点怪的东西,因为一个应用程序不一定只有一个窗口,而网页是确定只有一个窗口的,只需要在网页正中间上方显示即可,如果在WPF中要做一个可复用的消息提示其实还挺麻烦的

消息肯定会涉及参数传递,在Prism里肯定就是选择Region区域导航或者Messenger消息订阅

  • 如果确定只有一个窗口,或者像网页一样,所有内容都在窗口内显示,那么这个消息提示很简单,消息就像网页一样,只要调用显示就可以了
  • 如果要考虑多个窗口,麻烦的点在于要确定显示消息的窗口

Region

区域的话,只要通过RequestNavigate就可以指定执行的区域

Messenger

消息订阅有这么一个重载,filter可以作为条件判断是否执行

public virtual SubscriptionToken Subscribe(Action<TPayload> action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, Predicate<TPayload> filter)

但是涉及到组件复用,有些东西就不能写死,Region和Messenger都有同一个问题,如何将要显示消息的Window的标识传递到UserControl中?如果UserControl套娃又怎么传递?再加上View和ViewModel是分开的,感觉这是个死局呀
如果用循环或者递归往上找Window,似乎不符合MVVM的设计了
如果用Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);获取当前激活窗口,那么切到后台了呢?
感觉都不靠谱,不过仔细一想,确实没在多窗口应用程序上见过这种提示,去Google和Github,好像都是在桌面右下角的弹出提示,这种还是算了吧

案例

还真是个死局,还是写个单窗口的吧,就当是记录吧,这年头也流行这种,也方便跨平台

先来个消息类型MessageType,用来确定消息类型

public enum MessageType
{
    Info = 0,
    Warning = 1,
    Success = 2,
    Error = 4,
}

再来个消息命令MessageCommand,用来确定事件

public enum MessageCommand
{
    Close = 0,
    Open = 1,
}

至于要不要一个Model,我这里直接用ViewModel了,MessageViewModel这里就是用来绑定的数据,至于颜色这里我偷懒写死了,合理的写法应该是写资源字典,这样能根据主题切换

public class MessageViewModel : BindableBase
{
    private string _message;
    /// <summary>
    /// 消息
    /// </summary>
    public string Message
    {
        get { return _message; }
        set
        {
            _message = value;
            this.RaisePropertyChanged(nameof(Message));
        }
    }

    private MessageCommand _messageCommand;
    /// <summary>
    /// 消息命令
    /// </summary>
    public MessageCommand MessageCommand
    {
        get { return _messageCommand; }
        set
        {
            _messageCommand = value;
            this.RaisePropertyChanged(nameof(MessageCommand));
        }
    }


    private MessageType _messageType;
    /// <summary>
    /// 消息类型
    /// </summary>
    public MessageType MessageType
    {
        get { return _messageType; }
        set
        {
            _messageType = value;
            this.RaisePropertyChanged(nameof(MessageType));

            this.ChangeMessageStyle();
        }
    }

    private int _duration;
    /// <summary>
    /// 持续时间
    /// </summary>
    public int Duration
    {
        get { return _duration; }
        set
        {
            _duration = value;
            this.RaisePropertyChanged(nameof(Duration));
        }
    }

    private PackIconKind _icon;
    /// <summary>
    /// 图标
    /// </summary>
    public PackIconKind Icon
    {
        get { return _icon; }
        set
        {
            _icon = value;
            this.RaisePropertyChanged(nameof(Icon));
        }
    }

    private string _backgroundColor;
    /// <summary>
    /// 背景颜色
    /// </summary>
    public string BackgroundColor
    {
        get { return _backgroundColor; }
        set
        {
            _backgroundColor = value;
            this.RaisePropertyChanged(nameof(BackgroundColor));
        }
    }

    private string _foregroundColor;
    /// <summary>
    /// 字体颜色
    /// </summary>
    public string ForegroundColor
    {
        get { return _foregroundColor; }
        set
        {
            _foregroundColor = value;
            this.RaisePropertyChanged(nameof(ForegroundColor));
        }
    }

    private Visibility _visibilityStatus;
    /// <summary>
    /// 显示状态
    /// </summary>
    public Visibility VisibilityStatus
    {
        get { return _visibilityStatus; }
        set
        {
            _visibilityStatus = value;
            this.RaisePropertyChanged(nameof(VisibilityStatus));
        }
    }

    private Visibility _closeButtonVisibility;
    /// <summary>
    /// 关闭按钮显示状态
    /// </summary>
    public Visibility CloseButtonVisibility
    {
        get { return _closeButtonVisibility; }
        set
        {
            _closeButtonVisibility = value;
            this.RaisePropertyChanged(nameof(CloseButtonVisibility));
        }
    }

    /// <summary>
    /// 关闭消息命令
    /// </summary>
    public DelegateCommand CloseMessageCommand { get; set; }

    public MessageViewModel()
    {
        this.Message = string.Empty;
        this.MessageType = MessageType.Info;
        this.Duration = 3000;
        this.CloseButtonVisibility = Visibility.Visible;
        this.VisibilityStatus = Visibility.Visible;

        this.CloseMessageCommand = new DelegateCommand(this.CloseMessageCommandExecute);
    }

    /// <summary>
    /// 关闭命令事件处理器
    /// </summary>
    private void CloseMessageCommandExecute()
    {
        MessageHelper.CloseMessage(this);
    }

    /// <summary>
    /// 改变消息样式
    /// </summary>
    private void ChangeMessageStyle()
    {
        switch (this.MessageType)
        {
            case MessageType.Info:
                this.Icon = PackIconKind.Information;
                this.BackgroundColor = "#f4f4f5";
                this.ForegroundColor = "#909399";
                break;
            case MessageType.Warning:
                this.Icon = PackIconKind.AlertCircle;
                this.BackgroundColor = "#fdf6ec";
                this.ForegroundColor = "#e6a23c";
                break;
            case MessageType.Success:
                this.Icon = PackIconKind.CheckboxMarkedCircle;
                this.BackgroundColor = "#f0f9eb";
                this.ForegroundColor = "#67c23a";
                break;
            case MessageType.Error:
                this.Icon = PackIconKind.CloseCircle;
                this.BackgroundColor = "#fef0f0";
                this.ForegroundColor = "#f56c6c";
                break;
            default:
                break;
        }
    }
}

给这个Model或者ViewModel准备消息事件MessageEvent

public class MessageEvent : PubSubEvent<MessageViewModel>
{
}

再来个工具类MessageHelper操作消息事件

public class MessageHelper
{
    private readonly static IEventAggregator _eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();

    /// <summary>
    /// 初始化MessageViewModel
    /// </summary>
    /// <param name="message"></param>
    /// <param name="duration"></param>
    /// <param name="isCloseButtonVisibility"></param>
    /// <returns></returns>
    private static MessageViewModel InitMessageViewModel(string message, int duration = 3000, bool isCloseButtonVisibility = false)
    {
        var messageViewModel = new MessageViewModel();
        messageViewModel.Message = message;
        messageViewModel.Duration = duration;
        messageViewModel.MessageType = MessageType.Info;

        switch (isCloseButtonVisibility)
        {
            case false:
                messageViewModel.CloseButtonVisibility = Visibility.Collapsed;
                break;
            case true:
                messageViewModel.CloseButtonVisibility = Visibility.Visible;
                break;
            default:
                break;
        }

        return messageViewModel;
    }

    /// <summary>
    /// Info类型消息
    /// </summary>
    /// <param name="message"></param>
    /// <param name="duration"></param>
    /// <param name="isCloseButtonVisibility"></param>
    public static void Info(string message, int duration = 3000, bool isCloseButtonVisibility = false)
    {
        var messageViewModel = MessageHelper.InitMessageViewModel(message, duration, isCloseButtonVisibility);
        messageViewModel.MessageType = MessageType.Info;

        MessageHelper.PublishMessage(messageViewModel);
    }

    /// <summary>
    /// Warning类型消息
    /// </summary>
    /// <param name="message"></param>
    /// <param name="duration"></param>
    /// <param name="isCloseButtonVisibility"></param>
    public static void Warning(string message, int duration = 3000, bool isCloseButtonVisibility = false)
    {
        var messageViewModel = MessageHelper.InitMessageViewModel(message, duration, isCloseButtonVisibility);
        messageViewModel.MessageType = MessageType.Warning;

        MessageHelper.PublishMessage(messageViewModel);
    }

    /// <summary>
    /// Success类型消息
    /// </summary>
    /// <param name="message"></param>
    /// <param name="duration"></param>
    /// <param name="isCloseButtonVisibility"></param>
    public static void Success(string message, int duration = 3000, bool isCloseButtonVisibility = false)
    {
        var messageViewModel = MessageHelper.InitMessageViewModel(message, duration, isCloseButtonVisibility);
        messageViewModel.MessageType = MessageType.Success;

        MessageHelper.PublishMessage(messageViewModel);
    }

    /// <summary>
    /// 错误消息
    /// </summary>
    /// <param name="message"></param>
    /// <param name="duration"></param>
    /// <param name="isCloseButtonVisibility"></param>
    public static void Error(string message, int duration = 3000, bool isCloseButtonVisibility = false)
    {
        var messageViewModel = MessageHelper.InitMessageViewModel(message, duration, isCloseButtonVisibility);
        messageViewModel.MessageType = MessageType.Error;

        MessageHelper.PublishMessage(messageViewModel);
    }

    /// <summary>
    /// 发布消息
    /// </summary>
    /// <param name="messageViewModel"></param>
    private static void PublishMessage(MessageViewModel messageViewModel)
    {
        messageViewModel.MessageCommand = MessageCommand.Open;
        MessageHelper._eventAggregator.GetEvent<MessageEvent>().Publish(messageViewModel);
    }

    /// <summary>
    /// 关闭消息
    /// </summary>
    /// <param name="messageViewModel"></param>
    public static void CloseMessage(MessageViewModel messageViewModel)
    {
        messageViewModel.MessageCommand = MessageCommand.Close;
        MessageHelper._eventAggregator.GetEvent<MessageEvent>().Publish(messageViewModel);
    }
}

对应的界面MessageView

<UserControl
    x:Class="BlankApp2.Views.MessageView"
    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:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:BlankApp2.Views"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="http://prismlibrary.com/"
    Visibility="{Binding VisibilityStatus}"
    mc:Ignorable="d">
    <Border
        Width="auto"
        Height="auto"
        MinWidth="200"
        MinHeight="60"
        Background="{Binding BackgroundColor}"
        BorderBrush="{Binding ForegroundColor}"
        BorderThickness="2"
        CornerRadius="10">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="50" />
            </Grid.ColumnDefinitions>

            <StackPanel Grid.Column="0" Orientation="Horizontal">
                <materialDesign:PackIcon
                    Width="20"
                    Height="20"
                    Margin="20,0,20,0"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Center"
                    Foreground="{Binding ForegroundColor}"
                    Kind="{Binding Icon}" />

                <TextBlock
                    VerticalAlignment="Center"
                    FontSize="14"
                    Foreground="{Binding ForegroundColor}"
                    Text="{Binding Message}" />
            </StackPanel>

            <Button
                Grid.Column="1"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Command="{Binding CloseMessageCommand}"
                Style="{StaticResource MaterialDesignToolButton}"
                Visibility="{Binding CloseButtonVisibility}">
                <Button.Content>
                    <materialDesign:PackIcon
                        Width="20"
                        Height="20"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        Foreground="{Binding ForegroundColor}"
                        Kind="Close" />

                </Button.Content>
            </Button>

        </Grid>

    </Border>
</UserControl>

消息打算以列表形式存在,所以再来一个MessageListViewModel,这里处理消息事件

public class MessageListViewModel : BindableBase
{
    private readonly IEventAggregator _eventAggregator;

    private ObservableCollection<MessageViewModel> _messageViewModelList;
    /// <summary>
    /// 消息集合
    /// </summary>
    public ObservableCollection<MessageViewModel> MessageViewModelList
    {
        get { return _messageViewModelList; }
        set
        {
            _messageViewModelList = value;
            this.RaisePropertyChanged(nameof(MessageViewModelList));
        }
    }

    public MessageListViewModel(IEventAggregator eventAggregator)
    {
        this._eventAggregator = eventAggregator;

        this.MessageViewModelList = new ObservableCollection<MessageViewModel>();

        this._eventAggregator.GetEvent<MessageEvent>().Subscribe(arg => this.ShowMessage(arg), filter: arg => MessageCommand.Open == arg.MessageCommand);
        this._eventAggregator.GetEvent<MessageEvent>().Subscribe(arg => this.CloseMessage(arg), filter: arg => MessageCommand.Close == arg.MessageCommand);
    }

    /// <summary>
    /// 显示消息
    /// </summary>
    /// <param name="messageViewModel"></param>
    private void ShowMessage(MessageViewModel messageViewModel)
    {
        this.MessageViewModelList.Add(messageViewModel);

        this.AutoCloseMessage(messageViewModel);
    }

    /// <summary>
    /// 关闭消息
    /// </summary>
    /// <param name="messageViewModel"></param>
    private void CloseMessage(MessageViewModel messageViewModel)
    {
        this.MessageViewModelList.Remove(messageViewModel);
    }


    /// <summary>
    /// 自动关闭消息
    /// </summary>
    /// <param name="messageViewModel"></param>
    private async void AutoCloseMessage(MessageViewModel messageViewModel)
    {
        await Task.Delay(messageViewModel.Duration);
        MessageHelper.CloseMessage(messageViewModel);
    }
}

对应的界面MessageListView,这里手动绑定了MessageView的ViewModel,所以上面的MessageView的自动绑定ViewModel要关掉

<UserControl
    x:Class="BlankApp2.Views.MessageListView"
    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:local="clr-namespace:BlankApp2.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="http://prismlibrary.com/"
    d:DesignHeight="450"
    d:DesignWidth="800"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d">
    <ItemsControl ItemsSource="{Binding MessageViewModelList}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <local:MessageView HorizontalAlignment="Center" DataContext="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

主界面MainView,只有几个按钮

<Window
    x:Class="BlankApp2.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:BlankApp2.Views"
    xmlns:prism="http://prismlibrary.com/"
    Title="{Binding Title}"
    Width="600"
    Height="500"
    prism:ViewModelLocator.AutoWireViewModel="True">
    <Canvas x:Name="MainCanvas">
        <Canvas
            x:Name="MainMessageCanvas"
            Width="{Binding Path=ActualWidth, ElementName=MainCanvas}"
            Height="{Binding Path=ActualHeight, ElementName=MainCanvas}"
            HorizontalAlignment="Center"
            Panel.ZIndex="999">
            <local:MessageListView Width="{Binding ActualWidth, ElementName=MainMessageCanvas}" />
        </Canvas>

        <ContentControl prism:RegionManager.RegionName="{Binding MainContentRegionName}" />

        <StackPanel Canvas.Bottom="0" Orientation="Horizontal">
            <Button
                Background="Gray"
                Command="{Binding InfoCommand}"
                Content="Info" />
            <Button
                Margin="20,0,0,0"
                Background="Orange"
                Command="{Binding WarningCommand}"
                Content="Warning" />
            <Button
                Margin="20,0,0,0"
                Background="Green"
                Command="{Binding SuccessCommand}"
                Content="Success" />
            <Button
                Margin="20,0,0,0"
                Background="Red"
                Command="{Binding ErrorCommand}"
                Content="Error" />
        </StackPanel>

    </Canvas>
</Window>

还有MainViewModel,这里绑定点击事件处理器

public class MainViewModel : BindableBase
{
    private string _title;
    public string Title
    {
        get { return _title; }
        set { SetProperty(ref _title, value); }
    }


    private string _mainContentRegionName;

    public string MainContentRegionName
    {
        get { return _mainContentRegionName; }
        set
        {
            _mainContentRegionName = value;
            this.RaisePropertyChanged(nameof(MainContentRegionName));
        }
    }

    public DelegateCommand InfoCommand { get; set; }
    public DelegateCommand WarningCommand { get; set; }
    public DelegateCommand SuccessCommand { get; set; }
    public DelegateCommand ErrorCommand { get; set; }


    public MainViewModel()
    {
        this.Title = "测试";
        this.MainContentRegionName = "MainContentRegion";

        this.InfoCommand = new DelegateCommand(this.InfoCommandExecute);
        this.WarningCommand = new DelegateCommand(this.WarningCommandExecute);
        this.SuccessCommand = new DelegateCommand(this.SuccessCommandExecute);
        this.ErrorCommand = new DelegateCommand(this.ErrorCommandExecute);


    }

    public void InfoCommandExecute()
    {
        MessageHelper.Info("这是一条Info消息", isCloseButtonVisibility: true);
    }
    public void WarningCommandExecute()
    {
        MessageHelper.Warning("这是一条Warning消息");
    }
    public void SuccessCommandExecute()
    {
        MessageHelper.Success("这是一条Success消息");
    }
    public void ErrorCommandExecute()
    {
        MessageHelper.Error("这是一条Error消息");
    }
}

效果

我就不放gif了,也没做动画效果,就是个消息的显示和消失

WPF消息提示 结束

标签:messageViewModel,提示,MessageHelper,MessageType,private,消息,WPF,public
From: https://www.cnblogs.com/zzy-tongzhi-cnblog/p/17585626.html

相关文章

  • Photoshop启动时提示"Creative Cloud已丢失或损坏"
    问题Photoshop启动时,提示CreativeCloud已丢失或损坏 解决方案右键任务栏->任务管理器->右键进程"CreativeCloud"->打开文件所在的位置一般会打开路径..\CommonFiles\Adobe\AdobeDesktopCommon\ADS删除AdobeDesktopService.exe文件*要先关闭报错的弹窗,否则......
  • 工控 上位机 WPF 跑马灯的实现
    工控上位机WPF跑马灯的实现 工业控制软件中,跑马灯是主界面比不可少的组件。本文基于WPF技术,讲解如何实现高效的跑马灯组件。 跑马灯的效果如下图: 在讲解如何实现之前,我们先看一下,跑马灯组件在主界面上是如何使用的,请看如下代码:<BorderGrid.Row=......
  • WPF svg转path(快速生成Path代码的方法)
    在使用WPF的Path作图时,我们可能会拿到美工出的一些比较复杂的图,今天查阅网上发现svg是可以自动转path的,特作记录。github:https://github.com/BerndK/SvgToXaml    设置途中项目为启动项目,然后点击svg图片 你是不是以为复制上面的M0,0一直到Z就OK了!那,我就不会写这篇......
  • 国标GB28181平台LntonGBS(源码版)国标视频平台在连接MySQL数据库时提示“can’t connect
    LntonGBS国标视频云服务平台不仅支持无缝、完整接入内网或者公网的国标设备,还能够实现全平台、全终端输出。该平台支持将GB/T28181的设备/平台推送的PS流转成ES流,并提供RTSP、RTMP、FLV、HLS、WebRTC等多种格式视频流的分发服务,实现Web浏览器、手机浏览器、微信端、PC客户端等各终......
  • redis stream做轻量级消息队列的可行性
    背景对于消息数量很少的场景,尝试使用redisstream来做消息队列.为什么要用redis的stream,redis的其他数据结构可以吗?参考文章1:https://www.zhihu.com/question/43688764?sort=created参考文章2:https://www.cnblogs.com/williamjie/p/11201654.htmlredis有一些机制有队......
  • MQTT:轻量级消息传输协议在物联网中的应用
    随着物联网技术的发展,越来越多的设备需要进行实时通信和数据交换。在这样的背景下,MQTT(MessageQueuingTelemetryTransport)作为一种轻量级的消息传输协议,逐渐成为物联网领域的热门选择。本文将介绍MQTT协议的基本概念、特点以及在物联网中的应用,同时通过代码实例演示如何使用MQTT......
  • 消息队列详解
    文章目录1、什么是消息队列2、消息队列特点3、消息队列的的传输模式4、常用的消息队列1、什么是消息队列消息队列一般简称为MQ(MessgesQueue),是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成,是在消息的传输过程中保存消息的容器。......
  • 客服如何通过微信接收消息通知-唯一客服文档中心
    当我们在自己网站上嵌入对接了客服代码,我们想要通过微信接收访客的消息提醒通知,可以通过扫描客服后台的微信二维码,即时收消息通知提醒。我们网站地址:gofly.v1kf.com客服后台后台主页面板,就展示了一个微信二维码,扫码关注公众号,就能将客服账号与微信公众号进行绑定,通过微信公众号......
  • WPF动态绑定隐藏或显示DataGrid一列
     因为datagridtemplatecolumn不在VirsualTree中,不能继承DataGrid的DataContext,所以想要绑定到datagridtemplatecolumn的visibility,需要添加一个代理 一、添加一個FrameworkElement的代理<Window.Resources><FrameworkElementx:Key="ProxyElement"DataContext......
  • AI绘画| 迪士尼风格|可爱头像【附Midjourney提示词】
    Midjourney案例分享图片预览迪士尼风格|可爱头像高清原图及关键词Prompt已经放在文末网盘,需要的自取在数字艺术的新时代,人工智能绘画已经迅速崭露头角。作为最先进的技术之一,AI绘画结合了艺术和科学,开启了一片全新的视觉探索领域。本篇文章将深入介绍AI绘画的迪士尼风格可爱......