4
4
using System . Threading ;
5
5
using System . Threading . Tasks ;
6
6
using System . Windows ;
7
+ using System . Windows . Input ;
7
8
8
9
namespace MaterialDesignThemes . Wpf
9
10
{
@@ -13,14 +14,15 @@ public class SnackbarMessageQueue : ISnackbarMessageQueue, IDisposable
13
14
private readonly HashSet < Snackbar2 > _pairedSnackbars = new HashSet < Snackbar2 > ( ) ;
14
15
private readonly Queue < SnackbarMessageQueueItem > _snackbarMessages = new Queue < SnackbarMessageQueueItem > ( ) ;
15
16
private readonly ManualResetEvent _disposedEvent = new ManualResetEvent ( false ) ;
17
+ private readonly ManualResetEvent _notPausedEvent = new ManualResetEvent ( true ) ;
16
18
private int _pauseCounter = 0 ;
17
19
private bool _isDisposed ;
18
20
19
21
public SnackbarMessageQueue ( ) : this ( TimeSpan . FromSeconds ( 3 ) )
20
22
{ }
21
23
22
24
public SnackbarMessageQueue ( TimeSpan messageDuration )
23
- {
25
+ {
24
26
_messageDuration = messageDuration ;
25
27
Task . Factory . StartNew ( Pump ) ;
26
28
}
@@ -38,18 +40,15 @@ internal Action Pair(Snackbar2 snackbar)
38
40
39
41
internal Action Pause ( )
40
42
{
41
- //TODO...dialogs, for example, can pause the "countdown" of an active message as they are hiding it
42
-
43
+ if ( _isDisposed ) return ( ) => { } ;
43
44
44
45
if ( Interlocked . Increment ( ref _pauseCounter ) == 1 )
45
- //TODO cease counting down
46
- Console . WriteLine ( "Paused" ) ;
46
+ _notPausedEvent . Set ( ) ;
47
47
48
48
return ( ) =>
49
49
{
50
50
if ( Interlocked . Decrement ( ref _pauseCounter ) == 0 )
51
- //TODO resume counting down
52
- Console . WriteLine ( "Paus realesed" ) ;
51
+ _notPausedEvent . Reset ( ) ;
53
52
} ;
54
53
}
55
54
@@ -79,12 +78,13 @@ public void Enqueue<TArgument>(object content, object actionContent, Action<TArg
79
78
}
80
79
81
80
var argumentType = actionArgument != null ? typeof ( TArgument ) : null ;
82
-
83
- _snackbarMessages . Enqueue ( new SnackbarMessageQueueItem ( content , actionContent , actionHandler , actionArgument , argumentType ) ) ;
81
+ _snackbarMessages . Enqueue ( new SnackbarMessageQueueItem ( content , actionContent , actionHandler ,
82
+ actionArgument , argumentType ) ) ;
84
83
_messageWaitingEvent . Set ( ) ;
85
84
}
86
85
87
86
private readonly ManualResetEvent _messageWaitingEvent = new ManualResetEvent ( false ) ;
87
+ private Tuple < SnackbarMessageQueueItem , DateTime > _latestShownItem ;
88
88
89
89
private async void Pump ( )
90
90
{
@@ -114,43 +114,110 @@ private async void Pump()
114
114
if ( snackbar != null )
115
115
{
116
116
var message = _snackbarMessages . Dequeue ( ) ;
117
- await Show ( snackbar , message ) ;
117
+ if ( _latestShownItem == null || ! Equals ( _latestShownItem . Item1 . Content , message . Content ) ||
118
+ ! Equals ( _latestShownItem . Item1 . ActionContent , message . ActionContent ) ||
119
+ _latestShownItem . Item2 <= DateTime . Now . Subtract ( _messageDuration ) )
120
+ {
121
+ await Show ( snackbar , message ) ;
122
+ _latestShownItem = new Tuple < SnackbarMessageQueueItem , DateTime > ( message , DateTime . Now ) ;
123
+ }
118
124
}
119
125
120
126
if ( _snackbarMessages . Count > 0 )
121
127
_messageWaitingEvent . Set ( ) ;
122
128
else
123
129
_messageWaitingEvent . Reset ( ) ;
124
- }
125
-
130
+ }
131
+ }
132
+
133
+ private class MouseNotOverManagedWaitHandle : IDisposable
134
+ {
135
+ private readonly ManualResetEvent _waitHandle ;
136
+ private Action _cleanUp ;
137
+
138
+ public MouseNotOverManagedWaitHandle ( UIElement uiElement )
139
+ {
140
+ if ( uiElement == null ) throw new ArgumentNullException ( nameof ( uiElement ) ) ;
141
+
142
+ uiElement . MouseEnter += UiElementOnMouseEnter ;
143
+ uiElement . MouseLeave += UiElementOnMouseLeave ;
144
+ _waitHandle = new ManualResetEvent ( ! uiElement . IsMouseOver ) ;
145
+
146
+ _cleanUp = ( ) =>
147
+ {
148
+ uiElement . MouseEnter -= UiElementOnMouseEnter ;
149
+ uiElement . MouseLeave -= UiElementOnMouseLeave ;
150
+ _waitHandle . Dispose ( ) ;
151
+ _cleanUp = ( ) => { } ;
152
+ } ;
153
+ }
154
+
155
+ public WaitHandle WaitHandle => _waitHandle ;
156
+
157
+ private void UiElementOnMouseLeave ( object sender , MouseEventArgs mouseEventArgs )
158
+ {
159
+ _waitHandle . Set ( ) ;
160
+ }
161
+
162
+ private void UiElementOnMouseEnter ( object sender , MouseEventArgs mouseEventArgs )
163
+ {
164
+ _waitHandle . Reset ( ) ;
165
+ }
166
+
167
+ public void Dispose ( )
168
+ {
169
+ _cleanUp ( ) ;
170
+ }
171
+ }
172
+
173
+ private class TimeSpanSpinManagedHandle : IDisposable
174
+ {
175
+ public TimeSpanSpinManagedHandle ( WaitHandle pausedWaitHandle )
176
+ {
177
+ //new System.Threading.Timer()
178
+
179
+
180
+
181
+ }
182
+
183
+
184
+
185
+ public void Dispose ( )
186
+ {
187
+ throw new NotImplementedException ( ) ;
188
+ }
126
189
}
127
190
128
191
private async Task Show ( Snackbar2 snackbar , SnackbarMessageQueueItem messageQueueItem )
129
192
{
130
- await Task . Run ( ( ) =>
193
+ await Task . Run ( async ( ) =>
131
194
{
132
195
var completedHandle = new ManualResetEvent ( false ) ;
133
196
//TODO set message on snackbar
134
- snackbar . Dispatcher . InvokeAsync ( ( ) =>
135
- {
197
+
198
+ var mouseNotOverManagedWaitHandle = await snackbar . Dispatcher . InvokeAsync ( ( ) =>
199
+ {
136
200
snackbar . SetCurrentValue ( Snackbar2 . MessageProperty , Create ( messageQueueItem ) ) ;
137
- snackbar . SetCurrentValue ( Snackbar2 . IsActiveProperty , true ) ;
201
+ snackbar . SetCurrentValue ( Snackbar2 . IsActiveProperty , true ) ;
202
+ return new MouseNotOverManagedWaitHandle ( snackbar ) ;
138
203
} ) ;
139
204
140
-
141
205
206
+ WaitHandle . WaitAll ( new WaitHandle [ ]
207
+ {
208
+ mouseNotOverManagedWaitHandle . WaitHandle ,
209
+ } ) ;
142
210
143
211
//TODO wait until 3 things:
144
- // (
145
- // * NOT PAUSED
212
+ // (
146
213
// * NOT MOUSE OVER
147
214
// * TIME SPAN COMPLETED -- PAUSE MUST KEEP UPPING TIMESPAN
148
215
// )
149
216
// OR
150
217
// * ACTION CLICK
151
218
152
219
//quick hack implementation
153
- _disposedEvent . WaitOne ( snackbar . ActivateStoryboardDuration . Add ( _messageDuration ) ) ;
220
+ _disposedEvent . WaitOne ( _messageDuration ) ;
154
221
155
222
156
223
//remove message on snackbar
@@ -166,7 +233,7 @@ await Task.Run(() =>
166
233
167
234
168
235
} ) ;
169
- }
236
+ }
170
237
171
238
private static SnackbarMessage Create ( SnackbarMessageQueueItem messageQueueItem )
172
239
{
@@ -179,8 +246,10 @@ private static SnackbarMessage Create(SnackbarMessageQueueItem messageQueueItem)
179
246
180
247
public void Dispose ( )
181
248
{
182
- _isDisposed = true ;
249
+ _isDisposed = true ;
183
250
_disposedEvent . Set ( ) ;
251
+ _disposedEvent . Dispose ( ) ;
252
+ _notPausedEvent . Dispose ( ) ;
184
253
}
185
254
}
186
255
}
0 commit comments