2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
4
using System . Drawing ;
5
+ using System . Drawing . Imaging ;
5
6
using System . Windows . Forms . VisualStyles ;
6
7
7
8
namespace System . Windows . Forms ;
8
9
9
10
public abstract partial class UpDownBase
10
11
{
11
12
/// <summary>
12
- /// A control representing the pair of buttons on the end of the upDownEdit control. This class handles
13
- /// drawing the updown buttons, and detecting mouse actions on these buttons. Acceleration on the buttons is
14
- /// handled. The control sends UpDownEventArgss to the parent UpDownBase class when a button is pressed, or
13
+ /// A control representing the pair of buttons on the end of the up-down edit control. This class handles
14
+ /// drawing the up-down buttons, and detecting mouse actions on these buttons. Acceleration on the buttons is
15
+ /// handled. The control sends UpDownEventArgs to the parent UpDownBase class when a button is pressed, or
15
16
/// when the acceleration determines that another event should be generated.
16
17
/// </summary>
17
18
internal partial class UpDownButtons : Control
@@ -28,13 +29,18 @@ internal partial class UpDownButtons : Control
28
29
private Timer ? _timer ; // generates UpDown events
29
30
private int _timerInterval ; // milliseconds between events
30
31
32
+ private Bitmap ? _cachedBitmap ;
33
+
31
34
private bool _doubleClickFired ;
32
35
36
+ /// <summary>
37
+ /// Initializes a new instance of the <see cref="UpDownButtons"/> class.
38
+ /// </summary>
39
+ /// <param name="parent">The parent <see cref="UpDownBase"/> control.</param>
33
40
internal UpDownButtons ( UpDownBase parent ) : base ( )
34
41
{
35
42
SetStyle ( ControlStyles . Opaque | ControlStyles . FixedHeight | ControlStyles . FixedWidth , true ) ;
36
43
SetStyle ( ControlStyles . Selectable , false ) ;
37
-
38
44
_parent = parent ;
39
45
}
40
46
@@ -47,9 +53,10 @@ public event UpDownEventHandler? UpDown
47
53
remove => _upDownEventHandler -= value ;
48
54
}
49
55
50
- /// <remarks>
51
- /// <para>Called when the mouse button is pressed - we need to start spinning the value of the updown.</para>
52
- /// </remarks>
56
+ /// <summary>
57
+ /// Called when the mouse button is pressed - we need to start spinning the value of the up-down control.
58
+ /// </summary>
59
+ /// <param name="e">The mouse event arguments.</param>
53
60
private void BeginButtonPress ( MouseEventArgs e )
54
61
{
55
62
int half_height = Size . Height / 2 ;
@@ -73,16 +80,17 @@ private void BeginButtonPress(MouseEventArgs e)
73
80
// Generate UpDown event
74
81
OnUpDown ( new UpDownEventArgs ( ( int ) _pushed ) ) ;
75
82
76
- // Start the timer for new updown events
83
+ // Start the timer for new up-down events
77
84
StartTimer ( ) ;
78
85
}
79
86
87
+ /// <inheritdoc/>
80
88
protected override AccessibleObject CreateAccessibilityInstance ( )
81
89
=> new UpDownButtonsAccessibleObject ( this ) ;
82
90
83
- /// <remarks >
84
- /// <para> Called when the mouse button is released - we need to stop spinning the value of the updown.</para>
85
- /// </remarks >
91
+ /// <summary >
92
+ /// Called when the mouse button is released - we need to stop spinning the value of the up-down control.
93
+ /// </summary >
86
94
private void EndButtonPress ( )
87
95
{
88
96
_pushed = ButtonID . None ;
@@ -100,9 +108,10 @@ private void EndButtonPress()
100
108
101
109
/// <summary>
102
110
/// Handles detecting mouse hits on the buttons. This method detects
103
- /// which button was hit (up or down), fires a updown event, captures
104
- /// the mouse, and starts a timer for repeated updown events.
111
+ /// which button was hit (up or down), fires an up-down event, captures
112
+ /// the mouse, and starts a timer for repeated up-down events.
105
113
/// </summary>
114
+ /// <param name="e">The mouse event arguments.</param>
106
115
protected override void OnMouseDown ( MouseEventArgs e )
107
116
{
108
117
// Begin spinning the value
@@ -128,9 +137,10 @@ protected override void OnMouseDown(MouseEventArgs e)
128
137
_parent . OnMouseDown ( _parent . TranslateMouseEvent ( this , e ) ) ;
129
138
}
130
139
140
+ /// <inheritdoc/>
131
141
protected override void OnMouseMove ( MouseEventArgs e )
132
142
{
133
- // If the mouse is captured by the buttons (i.e. an updown button
143
+ // If the mouse is captured by the buttons (i.e. an up-down button
134
144
// was pushed, and the mouse button has not yet been released),
135
145
// determine the new state of the buttons depending on where
136
146
// the mouse pointer has moved.
@@ -149,7 +159,7 @@ protected override void OnMouseMove(MouseEventArgs e)
149
159
// Test if the mouse has moved outside the button area
150
160
if ( rect . Contains ( e . X , e . Y ) )
151
161
{
152
- // Inside button, repush the button if necessary
162
+ // Inside button, re-push the button if necessary
153
163
if ( _pushed != _captured )
154
164
{
155
165
// Restart the timer
@@ -163,11 +173,11 @@ protected override void OnMouseMove(MouseEventArgs e)
163
173
{
164
174
// Outside button
165
175
//
166
- // Retain the capture, but pop the button up whilst the mouse
176
+ // Retain the capture, but pop the button up while the mouse
167
177
// remains outside the button and the mouse button remains pressed.
168
178
if ( _pushed != ButtonID . None )
169
179
{
170
- // Stop the timer for updown events
180
+ // Stop the timer for up-down events
171
181
StopTimer ( ) ;
172
182
173
183
_pushed = ButtonID . None ;
@@ -204,6 +214,7 @@ protected override void OnMouseMove(MouseEventArgs e)
204
214
/// <summary>
205
215
/// Handles detecting when the mouse button is released.
206
216
/// </summary>
217
+ /// <param name="e">The mouse event arguments.</param>
207
218
protected override void OnMouseUp ( MouseEventArgs e )
208
219
{
209
220
if ( ! _parent . ValidationCancelled && e . Button == MouseButtons . Left )
@@ -239,6 +250,7 @@ protected override void OnMouseUp(MouseEventArgs e)
239
250
_parent . OnMouseUp ( me ) ;
240
251
}
241
252
253
+ /// <inheritdoc/>
242
254
protected override void OnMouseLeave ( EventArgs e )
243
255
{
244
256
_mouseOver = ButtonID . None ;
@@ -250,12 +262,40 @@ protected override void OnMouseLeave(EventArgs e)
250
262
/// <summary>
251
263
/// Handles painting the buttons on the control.
252
264
/// </summary>
265
+ /// <param name="e">The paint event arguments.</param>
266
+ #pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
253
267
protected override void OnPaint ( PaintEventArgs e )
254
268
{
255
269
int half_height = ClientSize . Height / 2 ;
256
270
257
271
// Draw the up and down buttons
258
- if ( Application . RenderWithVisualStyles )
272
+ if ( Application . IsDarkModeEnabled || ! Application . RenderWithVisualStyles )
273
+ {
274
+ Graphics cachedGraphics = EnsureCachedBitmap (
275
+ _parent . _defaultButtonsWidth ,
276
+ ClientSize . Height ) ;
277
+
278
+ ControlPaint . DrawScrollButton (
279
+ cachedGraphics ,
280
+ new Rectangle ( 0 , 0 , _parent . _defaultButtonsWidth , half_height ) ,
281
+ ScrollButton . Up ,
282
+ _pushed == ButtonID . Up
283
+ ? ButtonState . Pushed
284
+ : ( Enabled ? ButtonState . Normal : ButtonState . Inactive ) ) ;
285
+
286
+ ControlPaint . DrawScrollButton (
287
+ cachedGraphics ,
288
+ new Rectangle ( 0 , half_height , _parent . _defaultButtonsWidth , half_height ) ,
289
+ ScrollButton . Down ,
290
+ _pushed == ButtonID . Down
291
+ ? ButtonState . Pushed
292
+ : ( Enabled ? ButtonState . Normal : ButtonState . Inactive ) ) ;
293
+
294
+ e . GraphicsInternal . DrawImageUnscaled (
295
+ _cachedBitmap ,
296
+ new Point ( 0 , 0 ) ) ;
297
+ }
298
+ else
259
299
{
260
300
VisualStyleRenderer vsr = new ( _mouseOver == ButtonID . Up
261
301
? VisualStyleElement . Spin . Up . Hot
@@ -296,20 +336,7 @@ protected override void OnPaint(PaintEventArgs e)
296
336
new Rectangle ( 0 , half_height , _parent . _defaultButtonsWidth , half_height ) ,
297
337
HWNDInternal ) ;
298
338
}
299
- else
300
- {
301
- ControlPaint . DrawScrollButton (
302
- e . GraphicsInternal ,
303
- new Rectangle ( 0 , 0 , _parent . _defaultButtonsWidth , half_height ) ,
304
- ScrollButton . Up ,
305
- _pushed == ButtonID . Up ? ButtonState . Pushed : ( Enabled ? ButtonState . Normal : ButtonState . Inactive ) ) ;
306
-
307
- ControlPaint . DrawScrollButton (
308
- e . GraphicsInternal ,
309
- new Rectangle ( 0 , half_height , _parent . _defaultButtonsWidth , half_height ) ,
310
- ScrollButton . Down ,
311
- _pushed == ButtonID . Down ? ButtonState . Pushed : ( Enabled ? ButtonState . Normal : ButtonState . Inactive ) ) ;
312
- }
339
+ #pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
313
340
314
341
if ( half_height != ( ClientSize . Height + 1 ) / 2 )
315
342
{
@@ -329,12 +356,45 @@ protected override void OnPaint(PaintEventArgs e)
329
356
base . OnPaint ( e ) ;
330
357
}
331
358
359
+ /// <summary>
360
+ /// Ensures that the Bitmap has the correct size and returns the Graphics object from that Bitmap.
361
+ /// </summary>
362
+ /// <param name="width"></param>
363
+ /// <param name="height"></param>
364
+ /// <returns></returns>
365
+ [ MemberNotNull ( nameof ( _cachedBitmap ) ) ]
366
+ private Graphics EnsureCachedBitmap ( int width , int height )
367
+ {
368
+ if ( _cachedBitmap is null || _cachedBitmap . Size != new Size ( width , height ) )
369
+ {
370
+ _cachedBitmap ? . Dispose ( ) ;
371
+ _cachedBitmap = new Bitmap ( width , height , PixelFormat . Format32bppArgb ) ;
372
+ }
373
+
374
+ return Graphics . FromImage ( _cachedBitmap ) ;
375
+ }
376
+
377
+ protected override void Dispose ( bool disposing )
378
+ {
379
+ base . Dispose ( disposing ) ;
380
+ if ( disposing )
381
+ {
382
+ _cachedBitmap ? . Dispose ( ) ;
383
+ _cachedBitmap = null ;
384
+ _timer ? . Dispose ( ) ;
385
+ _timer = null ;
386
+ _upDownEventHandler = null ;
387
+ }
388
+ }
389
+
332
390
/// <summary>
333
391
/// Occurs when the UpDown buttons are pressed and when the acceleration timer tick event is raised.
334
392
/// </summary>
393
+ /// <param name="upevent">The up-down event arguments.</param>
335
394
protected virtual void OnUpDown ( UpDownEventArgs upevent )
336
395
=> _upDownEventHandler ? . Invoke ( this , upevent ) ;
337
396
397
+ /// <inheritdoc/>
338
398
internal override void ReleaseUiaProvider ( HWND handle )
339
399
{
340
400
if ( IsAccessibilityObjectCreated
@@ -348,7 +408,7 @@ internal override void ReleaseUiaProvider(HWND handle)
348
408
}
349
409
350
410
/// <summary>
351
- /// Starts the timer for generating updown events
411
+ /// Starts the timer for generating up-down events.
352
412
/// </summary>
353
413
protected void StartTimer ( )
354
414
{
@@ -369,7 +429,7 @@ protected void StartTimer()
369
429
}
370
430
371
431
/// <summary>
372
- /// Stops the timer for generating updown events
432
+ /// Stops the timer for generating up-down events.
373
433
/// </summary>
374
434
protected void StopTimer ( )
375
435
{
@@ -383,11 +443,14 @@ protected void StopTimer()
383
443
_parent . OnStopTimer ( ) ;
384
444
}
385
445
446
+ /// <inheritdoc/>
386
447
internal override bool SupportsUiaProviders => true ;
387
448
388
449
/// <summary>
389
- /// Generates updown events when the timer calls this function.
450
+ /// Generates up-down events when the timer calls this function.
390
451
/// </summary>
452
+ /// <param name="source">The source of the event.</param>
453
+ /// <param name="args">The event arguments.</param>
391
454
private void TimerHandler ( object ? source , EventArgs args )
392
455
{
393
456
// Make sure we've got mouse capture
@@ -397,7 +460,7 @@ private void TimerHandler(object? source, EventArgs args)
397
460
return ;
398
461
}
399
462
400
- // onUpDown method calls customer's ValueCHanged event handler which might enter the message loop and
463
+ // OnUpDown method calls customer's ValueChanged event handler which might enter the message loop and
401
464
// process the mouse button up event, which results in timer being disposed
402
465
OnUpDown ( new UpDownEventArgs ( ( int ) _pushed ) ) ;
403
466
0 commit comments