WPF自定义控件三:消息提示框
阅读原文时间:2023年07月08日阅读:1

需求:实现全局消息提示框

public class Message
{
private static readonly Style infoStyle = (Style)Application.Current.Resources["InfoMessage"];
private static readonly Style warningStyle = (Style)Application.Current.Resources["WarningMessage"];
private static readonly Style successStyle = (Style)Application.Current.Resources["SuccessMessage"];
private static readonly Style errorStyle = (Style)Application.Current.Resources["ErrorMessage"];

    #region 全局  
    public static void Show(MessageType type, UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        if (millisecondTimeOut <= 0)  
        {  
            isClearable = true;  
        }

        MessageWindow messageWindow = MessageWindow.GetInstance();  
        messageWindow.Dispatcher.VerifyAccess();

        MessageCard messageCard;  
        switch (type)  
        {  
            default:  
            case MessageType.None:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable  
                };  
                break;  
            case MessageType.Info:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = infoStyle  
                };  
                break;  
            case MessageType.Warning:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = warningStyle  
                };  
                break;  
            case MessageType.Success:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = successStyle  
                };  
                break;  
            case MessageType.Error:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = errorStyle  
                };  
                break;  
        }

        messageWindow.AddMessageCard(messageCard, millisecondTimeOut);  
        messageWindow.Show();  
    }

    public static void Show(UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.None, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowInfo(UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Info, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowSuccess(UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Success, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowWarning(UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Warning, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowError(UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Error, element, millisecondTimeOut, isClearable);  
    }

    public static void Show(MessageType type, string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(type, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }

    public static void Show(string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.None, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }

    public static void ShowInfo(string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Info, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }

    public static void ShowSuccess(string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Success, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }

    public static void ShowWarning(string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Warning, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }

    public static void ShowError(string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(MessageType.Error, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }  
    #endregion

    #region 指定容器  
    public static void Show(string containerIdentifier, MessageType type, UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        if (!MessageContainer.Containers.ContainsKey(containerIdentifier))  
        {  
            return;  
        }

        if (millisecondTimeOut <= 0)  
        {  
            isClearable = true;  
        }

        Panel messagePanel = MessageContainer.Containers\[containerIdentifier\];  
        messagePanel.Dispatcher.VerifyAccess();

        MessageCard messageCard;  
        switch (type)  
        {  
            default:  
            case MessageType.None:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable  
                };  
                break;  
            case MessageType.Info:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = infoStyle  
                };  
                break;  
            case MessageType.Warning:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = warningStyle  
                };  
                break;  
            case MessageType.Success:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = successStyle  
                };  
                break;  
            case MessageType.Error:  
                messageCard = new MessageCard  
                {  
                    Content = element,  
                    IsClearable = isClearable,  
                    Style = errorStyle  
                };  
                break;  
        }

        messagePanel.Children.Add(messageCard);

        // 进入动画  
        Storyboard enterStoryboard = new Storyboard();

        DoubleAnimation opacityAnimation = new DoubleAnimation  
        {  
            From = 0,  
            To = 1,  
            Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        };  
        Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(UIElement.OpacityProperty));

        DoubleAnimation transformAnimation = new DoubleAnimation  
        {  
            From = -30,  
            To = Application.Current.MainWindow.Height / 2-100,  
            Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        };  
        Storyboard.SetTargetProperty(transformAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)"));

        enterStoryboard.Children.Add(opacityAnimation);  
        enterStoryboard.Children.Add(transformAnimation);  
        if (millisecondTimeOut > 0)  
        {  
            // 进入动画完成  
            enterStoryboard.Completed += async (sender, e) =>  
            {  
                await Task.Run(() =>  
                {  
                    Thread.Sleep(millisecondTimeOut);  
                });

                messagePanel.Children.Remove(messageCard);  
            };

        }

        messageCard.BeginStoryboard(enterStoryboard);  
        // 退出动画  
        //Storyboard exitStoryboard = new Storyboard();

        //DoubleAnimation exitOpacityAnimation = new DoubleAnimation  
        //{  
        //    From = 1,  
        //    To = Application.Current.MainWindow.Height / 2,  
        //    Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
        //    EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        //};  
        //Storyboard.SetTargetProperty(exitOpacityAnimation, new PropertyPath(UIElement.OpacityProperty));

        //DoubleAnimation exitTransformAnimation = new DoubleAnimation  
        //{  
        //    From = 0,  
        //    To = -30,  
        //    Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
        //    EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        //};  
        //Storyboard.SetTargetProperty(exitTransformAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)"));

        //exitStoryboard.Children.Add(exitOpacityAnimation);  
        //exitStoryboard.Children.Add(exitTransformAnimation);

        //if (millisecondTimeOut > 0)  
        //{  
        //    // 进入动画完成  
        //    enterStoryboard.Completed += async (sender, e) =>  
        //    {  
        //        await Task.Run(() =>  
        //        {  
        //            Thread.Sleep(millisecondTimeOut);  
        //        });

        //        messageCard.BeginStoryboard(exitStoryboard);  
        //    };

        //}

        // 退出动画完成  
        //exitStoryboard.Completed += (sender, e) =>  
        //{  
        //    messagePanel.Children.Remove(messageCard);  
        //};

        //messageCard.BeginStoryboard(enterStoryboard);  
    }

    public static void Show(string containerIdentifier, UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.None, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowInfo(string containerIdentifier, UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Info, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowSuccess(string containerIdentifier, UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Success, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowWarning(string containerIdentifier, UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Warning, element, millisecondTimeOut, isClearable);  
    }

    public static void ShowError(string containerIdentifier, UIElement element, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Error, element, millisecondTimeOut, isClearable);  
    }

    public static void Show(string containerIdentifier, MessageType type, string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, type, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }

    public static void Show(string containerIdentifier, string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.None, new TextBlock { Text = message }, millisecondTimeOut, isClearable);  
    }

    public static void ShowInfo(string containerIdentifier, string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Info, new TextBlock { Text = message, Foreground = new SolidColorBrush(Colors.White) }, millisecondTimeOut, isClearable);  
    }

    public static void ShowSuccess(string containerIdentifier, string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Success, new TextBlock { Text = message, Foreground = new SolidColorBrush(Colors.White) }, millisecondTimeOut, isClearable);  
    }

    public static void ShowWarning(string containerIdentifier, string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Warning, new TextBlock { Text = message, Foreground = new SolidColorBrush(Colors.White) }, millisecondTimeOut, isClearable);  
    }

    public static void ShowError(string containerIdentifier, string message, int millisecondTimeOut = 3000, bool isClearable = true)  
    {  
        Show(containerIdentifier, MessageType.Error, new TextBlock { Text = message, Foreground = new SolidColorBrush(Colors.White) }, millisecondTimeOut, isClearable);  
    }  
    #endregion  
}

public enum MessageType  
{  
    None = 0,  
    Info,  
    Success,  
    Warning,  
    Error  
}

1:创建名为MessageCard资源字典与MessageCard类

<Style x:Key="WarningMessage" TargetType="{x:Type local:MessageCard}" BasedOn="{StaticResource MessageCard}">  
    <Setter Property="ThemeColorBrush" Value="{StaticResource WarningBrush}"/>  
    <Setter Property="IconType" Value="ErrorWarningFill"/>//IOC提示类型  
    <Setter Property="IsShwoIcon" Value="True"/>

</Style>

<Style x:Key="SuccessMessage" TargetType="{x:Type local:MessageCard}" BasedOn="{StaticResource MessageCard}">  
    <Setter Property="ThemeColorBrush" Value="{StaticResource SuccessBrush}"/>  
    <Setter Property="IconType" Value="CheckboxCircleFill"/>  
    <Setter Property="IsShwoIcon" Value="True"/>

</Style>

<Style x:Key="ErrorMessage" TargetType="{x:Type local:MessageCard}" BasedOn="{StaticResource MessageCard}">  
    <Setter Property="ThemeColorBrush" Value="{StaticResource ErrorBrush}"/>  
    <Setter Property="IconType" Value="CloseCircleFill"/>  
    <Setter Property="IsShwoIcon" Value="True"/>

</Style>

<Style x:Key="InfoMessage" TargetType="{x:Type local:MessageCard}" BasedOn="{StaticResource MessageCard}">  
    <Setter Property="ThemeColorBrush" Value="{StaticResource InfoBrush}"/>  
    <Setter Property="IconType" Value="InformationFill"/>  
    <Setter Property="IsShwoIcon" Value="True"/>

</Style>

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Zt.UI.Silver.Utils;

namespace Zt.UI.Silver
{
public class MessageCard : ContentControl
{
public static readonly RoutedEvent CloseEvent;

    static MessageCard()  
    {  
        CloseEvent = EventManager.RegisterRoutedEvent("Close", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MessageCard));  
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MessageCard), new FrameworkPropertyMetadata(typeof(MessageCard)));  
    }

    #region 事件  
    // 关闭消息事件  
    public event RoutedEventHandler Close  
    {  
        add { base.AddHandler(MessageCard.CloseEvent, value); }  
        remove { base.RemoveHandler(MessageCard.CloseEvent, value); }  
    }  
    #endregion

    #region 依赖属性  
    public static readonly DependencyProperty CornerRadiusProperty =  
      DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(MessageCard), new PropertyMetadata(default(CornerRadius)));

    public CornerRadius CornerRadius  
    {  
        get { return (CornerRadius)GetValue(CornerRadiusProperty); }  
        set { SetValue(CornerRadiusProperty, value); }  
    }

    public static readonly DependencyProperty ThemeColorBrushProperty =  
        DependencyProperty.Register("ThemeColorBrush", typeof(SolidColorBrush), typeof(MessageCard), new PropertyMetadata(default(SolidColorBrush)));

    public SolidColorBrush ThemeColorBrush  
    {  
        get { return (SolidColorBrush)GetValue(ThemeColorBrushProperty); }  
        set { SetValue(ThemeColorBrushProperty, value); }  
    }

    public static readonly DependencyProperty IconTypeProperty =  
        DependencyProperty.Register("IconType", typeof(IconType), typeof(MessageCard), new PropertyMetadata(default(IconType)));

    public IconType IconType  
    {  
        get { return (IconType)GetValue(IconTypeProperty); }  
        set { SetValue(IconTypeProperty, value); }  
    }

    public static readonly DependencyProperty IsShwoIconProperty =  
        DependencyProperty.Register("IsShwoIcon", typeof(bool), typeof(MessageCard), new PropertyMetadata(default(bool)));

    public bool IsShwoIcon  
    {  
        get { return (bool)GetValue(IsShwoIconProperty); }  
        set { SetValue(IsShwoIconProperty, value); }  
    }

    public static readonly DependencyProperty IsClearableProperty =  
        DependencyProperty.Register("IsClearable", typeof(bool), typeof(MessageCard), new PropertyMetadata(default(bool), OnIsClearbleChanged));

    public bool IsClearable  
    {  
        get { return (bool)GetValue(IsClearableProperty); }  
        set { SetValue(IsClearableProperty, value); }  
    }

    private static void OnIsClearbleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  
    {  
        if (d is MessageCard messageCard)  
        {  
            RoutedEventHandler handle = (sender, args) =>  
            {  
                if (VisualTreeHelper.GetParent(messageCard) is Panel panel)  
                {  
                    // 退出动画  
                    Storyboard exitStoryboard = new Storyboard();

                    DoubleAnimation exitOpacityAnimation = new DoubleAnimation  
                    {  
                        From = 1,  
                        To = 0,  
                        Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
                        EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
                    };  
                    Storyboard.SetTargetProperty(exitOpacityAnimation, new PropertyPath(FrameworkElement.OpacityProperty));

                    DoubleAnimation exitTransformAnimation = new DoubleAnimation  
                    {  
                        From = 0,  
                        To = -30,  
                        Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
                        EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
                    };  
                    Storyboard.SetTargetProperty(exitTransformAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)"));

                    exitStoryboard.Children.Add(exitOpacityAnimation);  
                    exitStoryboard.Children.Add(exitTransformAnimation);

                    // 动画完成  
                    exitStoryboard.Completed += (a, b) =>  
                    {  
                        panel.Children.Remove(messageCard);  
                        RoutedEventArgs eventArgs = new RoutedEventArgs(MessageCard.CloseEvent, messageCard);  
                        messageCard.RaiseEvent(eventArgs);  
                    };

                    messageCard.BeginStoryboard(exitStoryboard);    // 执行动画  
                }  
            };  
            messageCard.Foreground =new SolidColorBrush( Colors.Black);  
            messageCard.Loaded += (sender, arg) =>  
            {  
                if (messageCard.Template.FindName("clearButton", messageCard) is Button clearButton)  
                {  
                    if (messageCard.IsClearable)  
                    {  
                        clearButton.Click += handle;  
                    }  
                    else  
                    {  
                        clearButton.Click -= handle;  
                    }  
                }  
            };

            messageCard.Unloaded += (sender, arg) =>  
            {  
                if (messageCard.Template.FindName("clearButton", messageCard) is Button clearButton)  
                {  
                    if (messageCard.IsClearable)  
                    {  
                        clearButton.Click -= handle;  
                    }  
                }  
            };  
        }  
    }  
    #endregion

}  

}

2:创建名为MessageWindow的窗体

<StackPanel x:Name="messageStackPanel" Margin="10">

</StackPanel>  

后台代码:

public partial class MessageWindow : Window
{
private static MessageWindow messageWindow = null;

    private MessageWindow()  
    {  
        InitializeComponent();  
    }

    public static MessageWindow GetInstance()  
    {  
        if (messageWindow == null)  
        {  
            messageWindow = new MessageWindow();  
        }  
        else if (!messageWindow.IsLoaded)  
        {  
            messageWindow = new MessageWindow();  
        }  
        return messageWindow;  
    }

    public void AddMessageCard(MessageCard messageCard, int millisecondTimeOut)  
    {  
        messageCard.Close += MessageCard\_Close;

        messageStackPanel.Children.Add(messageCard);

        // 进入动画  
        Storyboard enterStoryboard = new Storyboard();

        DoubleAnimation opacityAnimation = new DoubleAnimation  
        {  
            From = 0,  
            To = 1,  
            Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        };  
        Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(OpacityProperty));

        DoubleAnimation transformAnimation = new DoubleAnimation  
        {  
            From = -30,  
            To = 0,  
            Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        };  
        Storyboard.SetTargetProperty(transformAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)"));

        enterStoryboard.Children.Add(opacityAnimation);  
        enterStoryboard.Children.Add(transformAnimation);

        // 退出动画  
        Storyboard exitStoryboard = new Storyboard();

        DoubleAnimation exitOpacityAnimation = new DoubleAnimation  
        {  
            From = 1,  
            To = 0,  
            Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        };  
        Storyboard.SetTargetProperty(exitOpacityAnimation, new PropertyPath(OpacityProperty));

        DoubleAnimation exitTransformAnimation = new DoubleAnimation  
        {  
            From = 0,  
            To = -30,  
            Duration = new Duration(TimeSpan.FromMilliseconds(300)),  
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }  
        };  
        Storyboard.SetTargetProperty(exitTransformAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)"));

        exitStoryboard.Children.Add(exitOpacityAnimation);  
        exitStoryboard.Children.Add(exitTransformAnimation);

        // 进入动画完成  
        if (millisecondTimeOut > 0)  
        {  
            enterStoryboard.Completed += async (sender, e) =>  
            {  
                await Task.Run(() =>  
                {  
                    Thread.Sleep(millisecondTimeOut);  
                });

                Dispatcher.Invoke(() =>  
                {  
                    messageCard.BeginStoryboard(exitStoryboard);  
                });  
            };  
        }

        // 退出动画完成  
        exitStoryboard.Completed += (sender, e) =>  
        {  
            Dispatcher.Invoke(() =>  
            {  
                messageStackPanel.Children.Remove(messageCard);  
                if (messageStackPanel.Children.Count == 0)  
                {  
                    this.Close();  
                }  
            });  
        };

        messageCard.BeginStoryboard(enterStoryboard);  
    }

    /// <summary>  
    /// 消息卡片关闭按钮事件  
    /// </summary>  
    /// <param name="sender"></param>  
    /// <param name="e"></param>  
    private void MessageCard\_Close(object sender, RoutedEventArgs e)  
    {  
        if (messageStackPanel.Children.Count == 0)  
        {  
            this.Close();  
        }  
    }  
}

public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
    {  
        return DependencyProperty.UnsetValue;  
    }  
}

APP引用