C# wpf 实现自定义倒计时MessageBox

WPF 自定义MessageBox系列

第一节 简单MessageBox
第二节 倒计时MessageBox(本节)
第三节 自定义按钮的MessageBox
第四节 界面操作分离的MessageBox
第五节 替换系统的MessageBox



前言

本篇是在上一篇《C# wpf 实现简单自定义MessageBox》的基础上添加倒计时功能,有些应用场景会使用倒计时的消息框,这种通常需要我们自己实现,一般使用定时器就可以很容易实现倒计时的消息框了。


一、代码

1、MessageBox.xaml

<Window x:Class="WpfApp1.MessageBox"
        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:WpfApp1"
        mc:Ignorable="d"
        Title="MessageBox" 
        AllowsTransparency="True"
        Background="Transparent"
        ResizeMode="NoResize"
        ShowInTaskbar="False"
        Topmost="True"
        WindowStartupLocation="CenterScreen"
        Width="600"
        Height="260"
        WindowStyle="None"
        Closing="Window_Closing"
        Loaded="Window_Loaded"
        >
    <Viewbox>
        <Grid  Width="600" Height="260">
            <Border  Margin="10" Background="White"    >
                <Border.Effect>
                    <DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.5"/>
                </Border.Effect>
                <Grid Margin="20">
                    <TextBlock x:Name="TB_Context" Margin="0,0,0,40" Text="Ensure?"  HorizontalAlignment="Center"  VerticalAlignment="Center" FontSize="48"  Foreground="Gray"/>
                    <Button VerticalAlignment="Bottom"   Content=""  Tag="No"  Margin="-174,0,0,0" Height="64" Width="144"  Click="No_Button_Click"  Cursor="Hand"  >
                        <Button.Template>
                            <ControlTemplate  TargetType="{x:Type Button}">
                                <Border Name="Border" Background="White"  BorderBrush="#cccccc"  >
                                    <Border.Effect>
                                        <DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.2"/>
                                    </Border.Effect>
                                    <TextBlock  Name="text" Text="{Binding NoLeftTime.TotalSeconds,StringFormat='No({0})'}"  FontSize="24"    Foreground="Gray"  HorizontalAlignment="Center" VerticalAlignment="Center">
                                    </TextBlock>
                                </Border>
                                <ControlTemplate.Triggers>
                                    <DataTrigger Binding="{Binding NoLeftTime.TotalSeconds}" Value="-1">
                                        <Setter TargetName="text" Property="Text" Value="No"></Setter>
                                    </DataTrigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                    <Button VerticalAlignment="Bottom"    Content="Yes"  Tag="Yes"   Margin="174,0,0,0" Height="64" Width="144"  Click="Yes_Button_Click" Cursor="Hand">
                        <Button.Template>
                            <ControlTemplate  TargetType="{x:Type Button}">
                                <Border Name="Border" Background="Gray"  >
                                    <Border.Effect>
                                        <DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.2"/>
                                    </Border.Effect>
                                    <TextBlock  Name="text" Text="{Binding YesLeftTime.TotalSeconds,StringFormat='Yes({0})'}"  FontSize="24"    Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center">
                                    </TextBlock>
                                </Border>
                                <ControlTemplate.Triggers>
                                    <DataTrigger Binding="{Binding YesLeftTime.TotalSeconds}" Value="-1">
                                        <Setter TargetName="text" Property="Text" Value="Yes"></Setter>
                                    </DataTrigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                </Grid>
            </Border>
        </Grid>
    </Viewbox>
</Window>

2、MessageBox.xaml.cs

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Threading;
namespace WpfApp1
{
    public class MessageResult
    {
        /// <summary>
        /// 结果,Yes为true,No为false
        /// </summary>
        public bool IsYes { get; set; }
        public TimeSpan YesLeftTime { get; set; }

        public TimeSpan NoLeftTime { get; set; }
    }
    public class MessageBoxEventArgs : EventArgs
    {
        /// <summary>
        /// 结果,Yes为true,No为false
        /// </summary>
        public MessageResult Result { get; set; }
    }

    /// <summary>
    /// MessageBox.xaml 的交互逻辑
    /// </summary>
    public partial class MessageBox : Window, INotifyPropertyChanged
    {
        public  event EventHandler<MessageBoxEventArgs> Result;
        public event PropertyChangedEventHandler PropertyChanged;

        public string Context
        {
            get { return TB_Context.Text; }
            set { TB_Context.Text = value; }
        }
        TimeSpan _yesLeftTime = TimeSpan.FromSeconds(-1);
        public TimeSpan YesLeftTime 
        {
            get { return _yesLeftTime; }
            set { _yesLeftTime = value; PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("YesLeftTime"));}
        }
        TimeSpan _noLeftTime= TimeSpan.FromSeconds(-1);
        public TimeSpan NoLeftTime
        {
            get { return _noLeftTime; }
            set { _noLeftTime = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NoLeftTime")); }
        }
        bool _isLegal = false;
        DispatcherTimer _timer;
        public MessageBox()
        {
            InitializeComponent();
            DataContext = this;
      
        }
        
        public static void Show(string context, EventHandler<MessageBoxEventArgs> result)
        {
            var mb = new MessageBox();
            mb.Context = context;
            mb.Result += result;
            mb.Show();
        }

        public static MessageResult ShowDialog(string context)
        {

            return ShowDialog(context,null,null);
        }

        public static MessageResult ShowDialog(string context,TimeSpan ?yestCountDown, TimeSpan? noCountDown)
        {
            var mb = new MessageBox();
            mb.Context = context;
            MessageResult r = null;
            if(yestCountDown!=null)
            {
                mb.YesLeftTime = yestCountDown.Value;
            }
            if (noCountDown != null)
            {
                mb.NoLeftTime = noCountDown.Value;
            }
            mb.Result += (s, e) => {
                r = e.Result;
            };
            mb.ShowDialog();
            return r;
        }
        private void No_Button_Click(object sender, RoutedEventArgs e)
        {
            _isLegal = true;
            Close();
            Result?.Invoke(this, new MessageBoxEventArgs() { Result = new MessageResult() { IsYes=false, YesLeftTime=this.YesLeftTime, NoLeftTime= this.NoLeftTime } });
        }
        private void Yes_Button_Click(object sender, RoutedEventArgs e)
        {
            _isLegal = true;
            Close();
            Result?.Invoke(this, new MessageBoxEventArgs() { Result = new MessageResult() { IsYes = true, YesLeftTime = this.YesLeftTime, NoLeftTime = this.NoLeftTime } });
        }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = !_isLegal;
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if(YesLeftTime.TotalSeconds>0||NoLeftTime.TotalSeconds > 0)
            {
                _timer = new DispatcherTimer();
                _timer.Interval = TimeSpan.FromSeconds(1);
                _timer.Tick += (S, E) =>
                {         
                    if (YesLeftTime.TotalSeconds > 0)
                    {
                        YesLeftTime = YesLeftTime.Add(-TimeSpan.FromSeconds(1));
                    }
                    else if (YesLeftTime.TotalSeconds == 0)
                    {
                        _timer.Stop();
                        Yes_Button_Click(null, null);
                    }

                    if (NoLeftTime.TotalSeconds > 0)
                    {
                        NoLeftTime = NoLeftTime.Add(-TimeSpan.FromSeconds(1));
                    }
                    else if (NoLeftTime.TotalSeconds == 0)
                    {
                        _timer.Stop();
                        No_Button_Click(null, null);
                    }
                };
                _timer.Start();
            }
        }
    }
}

二、效果预览

在这里插入图片描述
在这里插入图片描述

三、调用方法

Yes倒计时30秒

var r = MessageBox.ShowDialog("Ensure?",TimeSpan.FromSeconds(30), null);
if (r.IsYes)
{
    //选择了Yes
}
else
{
    //选择了No
}

No倒计时30秒

var r = MessageBox.ShowDialog("Ensure?",null,TimeSpan.FromSeconds(30));
if (r.IsYes)
{
    //选择了Yes
}
else
{
    //选择了No
}


总结

使用了DispatcherTimer作为定时器,不用关系线程切换问题。总的来说还是比较容易实现的,虽然调用接口实现的比较简单,而且也考虑过按照系统的MessageBox接口来实现一套。但是个人认为Windows的MessageBox参数有点过于复杂,尤其是,OK、Cancel、Yes、No那一系列的按钮。与其使用那些固定的按钮,还不如定义几个灵活简单的可定制按钮。当然本篇文帐并没有做到这一点,这个将在下一篇文章中实现。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeOfCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值