WPF弹窗限流

  • ~4.12K 字
  1. 1. 核心逻辑
  2. 2. 实现代码
  3. 3. 优化逻辑
    1. 3.1. 思路:

在wpf开发中我们经常会通过弹窗给用户推送信息,有时候我们一些信息非常频繁,会出现弹窗轰炸的效果。

这时候我们可以把信息写到log里面,但通知到用户也是必要的,我们可以给相同的信息设置冷却时间和标识避免弹窗频繁弹出。

核心逻辑

  • 给信息定义标识
  • 记录此标识上一次弹窗时间
  • 若在冷却时间内不弹窗,仅记录次数

这里我们的弹窗用的是Notification.Wpf,这个库是fork的,但更新得比较好,推荐!

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using Notification.Wpf;

namespace NotificationThrottle.Services
{
public class NotificationThrottle
{
/// <summary>
/// 存储每个警告标识的最后弹窗时间和次数
/// </summary>
private readonly Dictionary<string, TrackInfo> _trackInfo = new Dictionary<string, TrackInfo>();
/// <summary>
/// 冷却时间
/// </summary>
private readonly TimeSpan _cooldown = TimeSpan.FromSeconds(10);

private readonly NotificationManager _notificationManager;

public NotificationThrottle(NotificationManager notificationManager)
{
_notificationManager = notificationManager;
}

/// <summary>
/// 过滤重复通知或重复类型的通知
/// </summary>
/// <param name="id"></param>
/// <param name="message"></param>
/// <param name="notificationType"></param>
public void ShowThrottledNotification(string id, string message,NotificationType notificationType=NotificationType.Information)
{
if(!_trackInfo.TryGetValue(id, out TrackInfo trackInfoValue))
{
trackInfoValue = new TrackInfo()
{
LastTime = DateTime.MinValue,
Count = 1
};
_trackInfo[id] = trackInfoValue;
}

TimeSpan elapsed = DateTime.Now - trackInfoValue.LastTime;
if (elapsed < _cooldown)
{
trackInfoValue.Count++;
return;
}

_notificationManager.Show(Enum.GetName(typeof(NotificationType), notificationType), $"{message}, 期间尝试弹出{trackInfoValue.Count}次", notificationType);

trackInfoValue.LastTime = DateTime.Now;
_trackInfo[id] = trackInfoValue;
}

private class TrackInfo
{
public DateTime LastTime { get; set; }
public int Count { get; set; }
}
}
}

提示

如果冷却时间需要可配置的话推荐注册单例服务。

不需要配置的话可以写成扩展方法。

扩展方法代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public static class NotificationManagerExtensions
{
/// <summary>
/// 存储每个警告标识的最后弹窗时间和次数
/// </summary>
private static readonly Dictionary<string, TrackInfo> _trackInfo = new Dictionary<string, TrackInfo>();
/// <summary>
/// 冷却时间
/// </summary>
private static readonly TimeSpan _cooldown = TimeSpan.FromSeconds(10);
public static void ShowThrottledNotification(this NotificationManager notificationManager, string id, string message, NotificationType notificationType = NotificationType.Information)
{
if (!_trackInfo.TryGetValue(id, out TrackInfo trackInfoValue))
{
trackInfoValue = new TrackInfo()
{
LastTime = DateTime.MinValue,
Count = 1
};
_trackInfo[id] = trackInfoValue;
}

TimeSpan elapsed = DateTime.Now - trackInfoValue.LastTime;
if (elapsed < _cooldown)
{
trackInfoValue.Count++;
return;
}

notificationManager.Show(Enum.GetName(typeof(NotificationType), notificationType), $"{message}, 期间尝试弹出{trackInfoValue.Count}次", notificationType);

trackInfoValue.LastTime = DateTime.Now;
_trackInfo[id] = trackInfoValue;
}

private class TrackInfo
{
public DateTime LastTime { get; set; }
public int Count { get; set; }
}
}

优化逻辑

在原有设置冷却时间的基础上我们其实可以动态调整冷却时间,可以更灵活的处理高频信息。

思路:

根据弹出信息触发频率延长冷却时间。

需要加字段基础冷却时间、最长冷却时间、触发次数阈值、延长倍率。

当尝试弹出触发次数大于触发阈值时延长冷却时间,但为了避免无限延长冷却时间我们设置最长冷却时间。

代码地址