-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcslibs.cs
143 lines (126 loc) · 4.78 KB
/
cslibs.cs
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace cslibs
{
/// <summary>
/// 手抜き(クラス)ライブラリ集
/// </summary>
public class UIBackTask<Targ, Tresult, Tnotice>
{
// UIでのバックグラウンドで動かすタスクのヘルパー
// 時間のかかる処理を、UIの裏で動かして、タスク立ち上げ、キャンセル、進捗通知、など必要な処理を定型的に実装するためのインターフェース
private Task<Tresult>? backtask;
private CancellationTokenSource? cancel_backtask;
private Form targetForm;
public UIBackTask(Form _f)
{
this.backtask = null;
this.cancel_backtask = null;
this.targetForm = _f;
this._noticefunc = null;
this._noticetime = new Stopwatch();
}
/// <summary>
/// バックグラウンドタスクが終わるまで待つ
/// </summary>
/// <param name="isFinished">UIでアプリをClose()するタイミングで呼び出す場合はtrue</param>
public void CanelAndWait(bool isFinished)
{
this.cancel_backtask?.Cancel();
if (isFinished)
{
while (this.backtask?.Wait(1) == false)
{
// UIを最後回す(これやらないと終わる直前にInvokeでUI側を呼び出すケースで終われなくなるため)
Application.DoEvents();
}
}
else
{
// UIなしなので待つだけ
this.backtask?.Wait();
}
}
private Action<Tnotice>? _noticefunc;
private Stopwatch _noticetime;
private Queue<Tnotice> nbuffer;
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
private bool NotifyFunc(Tnotice n)
{
// キャンセルチェック
if ( this.cancel_backtask != null)
{
CancellationToken _t = this.cancel_backtask.Token;
if (_t.IsCancellationRequested)
{
// キャンセルリクエストがあったら直ぐに終わる
return true;
}
}
// 沢山送りすぎるとまずいので、2msec.待つ
if ( this._noticetime.ElapsedMilliseconds >= 2 )
{
this._noticetime.Restart();
if (this._noticefunc != null)
{
this.nbuffer.Enqueue(n);
int cnt = 0;
while (this.nbuffer.Count > 0)
{
var _n = this.nbuffer.Dequeue();
this.targetForm.Invoke((Action)(() => this._noticefunc(_n)));
cnt++;
if ( cnt >= 30 )
{
// 30個で様子見
break;
}
}
}
} else
{
// メッセージがいっぱいで送れなかった
if (this._noticefunc != null)
{
this.nbuffer.Enqueue(n);
}
}
return false;
}
public Tresult Result {
get {
return this.backtask.Result;
}
}
/// <summary>
/// バックグラウンドタスクの実行開始
/// </summary>
/// <param name="execfunc">バックグラウンドタスク Tresult execfunc(Targ _arg, Func<Tnotice,bool> _nfunc) _nfunc は息継ぎ・通知関数です </param>
/// <param name="_arg">バックグラウンドタスク実行時に渡す引数</param>
/// <param name="noticefunc">UI通知関数 void noticefunc(Tnotice n)</param>
public void Execute(Func<Targ, Func<Tnotice, bool>, Tresult> execfunc, Targ _arg, Action<Tnotice> noticefunc)
{
this.cancel_backtask = new CancellationTokenSource();
this._noticefunc = noticefunc;
this._noticetime.Restart();
this.nbuffer = new Queue<Tnotice>();
this.backtask = Task.Factory.StartNew(() => {
var _r = execfunc(_arg, this.NotifyFunc);
// 通知を全部送りきる
foreach ( var _n in this.nbuffer)
{
this.targetForm.Invoke((Action)(() => this._noticefunc(_n)));
}
return _r;
});
}
}
}