试图创建一个类吐司通知,不能多次实例化。

问题描述 投票:0回答:1

我试图在WPF中创建一个Toast通知,我的问题是,如果我,在这种情况下,从数据库中删除的东西太快,当前的通知只是被升级与新的文本,而不是创建一个新的类的实例,所以我可以看到两个通知。

通知成为StackPanelf从MainWindow的一个子类,这样它总是有相同的位置。这就是为什么我在一开始就清除了子类。

这个类可以工作,只是我不能同时拥有一个以上的通知。

我错过了什么?对不起,我是个初学者,我自己试着做了这个。

这是我的类代码

{
   public class NotificationToast
    {
        public Border ToastBorder { get; set; }
        public Grid ToastGrid { get; set; }
        public TextBlock BodyBlock { get; set; }
        public String NotificationString { get; set; }
        public DoubleAnimation Animation1 { get; set; }
        public DoubleAnimation Animation2 { get; set; }
        public TranslateTransform Transformation1 { get; set; }
        public TranslateTransform Transformation2 { get; set; }

        public NotificationToast(MainWindow window, string notificationString)
        {
            InitializeWindow(window, notificationString);   
        }

        private void InitializeWindow(MainWindow window, string notificationString)
        {
            NotificationString = notificationString;
            ToastBorder = new Border();
            ToastBorder.Width = 250;
            ToastBorder.Height = 70;
            ToastBorder.BorderThickness = new Thickness(2);
            ToastBorder.BorderBrush = Brushes.IndianRed;
            ToastBorder.Background = new SolidColorBrush(Color.FromRgb(240, 143, 116));
            TextBlock BodyBlock = new TextBlock();
            BodyBlock.Width = 248;
            BodyBlock.Height = 68;
            BodyBlock.TextWrapping = TextWrapping.Wrap;
            BodyBlock.FontSize = 16;
            BodyBlock.Text = NotificationString;
            BodyBlock.Margin = new Thickness(5);

            ToastBorder.Child = BodyBlock;
            window.stackNotification.Children.Clear();
            window.stackNotification.Children.Add(ToastBorder);

            MovingIn(window.stackNotification);
            MovingOut(window.stackNotification);

        }

        private void MovingIn(StackPanel movingBorder)
        {
            TranslateTransform trans = new TranslateTransform();
            movingBorder.RenderTransform = trans;
            Animation1 = new DoubleAnimation(80, 0, TimeSpan.FromSeconds(1));
            trans.BeginAnimation(TranslateTransform.YProperty, Animation1);
        }
        private async void MovingOut(StackPanel movingBorder)
        {
            await Task.Delay(2500);

            TranslateTransform trans = new TranslateTransform();
            movingBorder.RenderTransform = trans;
            Animation2 = new DoubleAnimation(0, 80, TimeSpan.FromSeconds(1));
            trans.BeginAnimation(TranslateTransform.YProperty, Animation2);
        }
    }
}

然后我像这样调用这个类

WindowToast = new NotificationToast(ParentWindow, Convert.ToString("The Player " + PersonDetails.FirstName + " " + PersonDetails.LastName + " details has been updated."));
c# wpf class notifications toast
1个回答
1
投票

下面是一个简短的例子 吐司信息 使用 MVVM 编程模式。

Disclamer。 我是自己从头开始做的,我不是一个专业的程序员。WPF是我的爱好不是工作。因此,解决方案经过测试,但可能包含bug或不准确的实现。不要相信我。

由于模式方法的原因,我们需要两个辅助类。

// INPC interface implementation, used for notifying UI if some Property was changed.
public class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

// Needed for easy Commands use
public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
    public void Execute(object parameter) => _execute(parameter);
}

解决方案的特点。

  • 在右下角显示敬酒信息
  • 支持3种严重性。信息,警告,错误。信息的颜色取决于它。
  • 支持调整一次显示信息的最大数量。
  • 将收到的超过限制的信息进行排队,并在以后显示出来。
  • 用户可以立即关闭任何信息
  • 每条信息在10秒后消失
  • 增加了一些出现和消失的动画

注意:不支持并发,如从不同的ThreadsTasks推送消息。

  • 不支持并发,例如从不同的ThreadsTasks推送消息。
  • 不是一个用户控制或独立的解决方案。

...但你可以改进它。)

数据类。

public enum ToastMessageSeverity
{
    Info = 0,
    Warning = 1,
    Error = 2
}

public class ToastMessage
{
    public string Message { get; set; }
    public ToastMessageSeverity Severity { get; set; }
}

ToastViewModel

public class ToastViewModel : ReadOnlyObservableCollection<ToastMessage>
{
    private readonly ObservableCollection<ToastMessage> _items;
    private readonly int _maxCount;
    private readonly Queue<ToastMessage> _messagesQueue;
    private ICommand _removeItem;

    private void RemoveMessage(ToastMessage message)
    {
        if (_items.Contains(message))
        {
            _items.Remove(message);
            if (_messagesQueue.Count > 0) Push(_messagesQueue.Dequeue());
        }
    }

    public void Push(ToastMessage message)
    {
        if (_items.Count >= _maxCount)
            _messagesQueue.Enqueue(message);
        else
        {
            _items.Add(message);
            Task.Run(async () => await Task.Delay(10500)).ContinueWith(_ => RemoveMessage(message), TaskScheduler.FromCurrentSynchronizationContext());
        }
    }

    public ICommand RemoveItem => _removeItem ?? (_removeItem = new RelayCommand(parameter => 
    {
        if (parameter is ToastMessage message) RemoveMessage(message);
    }));

    public ToastViewModel() : this(6) { }
    public ToastViewModel(int maxCount) : this(new ObservableCollection<ToastMessage>(), maxCount) { }
    private ToastViewModel(ObservableCollection<ToastMessage> items, int maxCount) : base(items)
    {
        _items = items;
        _maxCount = maxCount;
        _messagesQueue = new Queue<ToastMessage>();
    }
}

MainViewModel

public class MainViewModel : NotifyPropertyChanged
{
    private ToastViewModel _toastMessages;
    private ICommand _pushToastCommand;
    public ToastViewModel ToastMessages
    {
        get => _toastMessages;
        set
        {
            _toastMessages = value;
            OnPropertyChanged();
        }
    }
    private int counter = 0;
    public ICommand PushToastCommand => _pushToastCommand ?? (_pushToastCommand = new RelayCommand(parameter =>
    {
        ToastMessageSeverity severity = ToastMessageSeverity.Info;
        if (parameter is string severityString)
        {
            foreach (ToastMessageSeverity tms in Enum.GetValues(typeof(ToastMessageSeverity)))
            {
                if (severityString == tms.ToString())
                {
                    severity = tms;
                    break;
                }
            }
        }
        ToastMessages.Push(new ToastMessage { Message = severity + " message " + counter++, Severity = severity });
    }));
    public MainViewModel()
    {
        ToastMessages = new ToastViewModel();
    }
}

和完整的标记(将允许复制整个应用程序)

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp1"
        Title="MainWindow" Height="600" Width="1000" WindowStartupLocation="CenterScreen">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid>
            <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Button Content="Info message" Command="{Binding PushToastCommand}" Padding="10,5" Margin="10" />
                <Button Content="Warning message" Command="{Binding PushToastCommand}" CommandParameter="Warning" Padding="10,5" Margin="10" />
                <Button Content="Error message" Command="{Binding PushToastCommand}" CommandParameter="Error" Padding="10,5" Margin="10" />
            </StackPanel>
        </Grid>
        <Grid>
            <ItemsControl ItemsSource="{Binding ToastMessages}" Margin="10" HorizontalAlignment="Right" VerticalAlignment="Bottom">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Border HorizontalAlignment="Right" >
                            <Border.Style>
                                <Style TargetType="Border">
                                    <Setter Property="BorderThickness" Value="2"/>
                                    <Setter Property="CornerRadius" Value="5"/>
                                    <Setter Property="Margin" Value="10,5"/>
                                    <Setter Property="Padding" Value="15,10"/>
                                    <Setter Property="MaxWidth" Value="300"/>
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Severity}" Value="Info">
                                            <Setter Property="BorderBrush" Value="CadetBlue"/>
                                            <Setter Property="Background" Value="LightCyan"/>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding Severity}" Value="Warning">
                                            <Setter Property="BorderBrush" Value="Orange"/>
                                            <Setter Property="Background" Value="LightYellow"/>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding Severity}" Value="Error">
                                            <Setter Property="BorderBrush" Value="Red"/>
                                            <Setter Property="Background" Value="LightPink"/>
                                        </DataTrigger>
                                        <EventTrigger RoutedEvent="Border.Loaded">
                                            <BeginStoryboard>
                                                <Storyboard>
                                                    <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.5" />
                                                    <ThicknessAnimation Storyboard.TargetProperty="Margin" From="10,15,10,-5" To="10,5" Duration="0:0:0.5" />
                                                    <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1.0" To="0.0" BeginTime="0:0:10" Duration="0:0:0.2" />
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </EventTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Border.Style>
                            <Grid>
                                <TextBlock Text="{Binding Message}" FontSize="16" TextWrapping="Wrap" />
                                <Button HorizontalAlignment="Right" VerticalAlignment="Top" Margin="-13" Command="{Binding ItemsSource.RemoveItem, RelativeSource={RelativeSource AncestorType=ItemsControl}}" CommandParameter="{Binding}">
                                    <Button.Template>
                                        <ControlTemplate>
                                            <TextBlock Text="×" FontSize="16" Foreground="{Binding BorderBrush, RelativeSource={RelativeSource AncestorType=Border}}" Cursor="Hand"/>
                                        </ControlTemplate>
                                    </Button.Template>
                                </Button>
                            </Grid>
                        </Border>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Grid>
    </Grid>
</Window>

[Toast messages[1]

而传统上,对于 MVVM 新人:代码后台类

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.