私はテキストボックスを備えたwinformを使用しており、textchangedでバックグラウンドスレッドを実行します:
private void txtFathersLast_TextChanged(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(_ => WaitWhileUserTyping());
}
private void WaitWhileUserTyping()
{
var keepWaiting = true;
while (keepWaiting)
{
_keyPressed = false;
Thread.Sleep(TypingDelay);
keepWaiting = _keyPressed;
}
Invoke((MethodInvoker)(ExecuteSearch));
_waiting = false;
}
private void ExecuteSearch()
{
Thread.Sleep(200);
Task.Factory.StartNew(() =>
{
using (DataReference.SearchWCF search = new DataReference.SearchWCF())
{
_similaritySearchResults = search.SearchPersonBySimilarity(txtFathersLast.Text, txtMothersLast.Text, txtName.Text, DateTime.Now, 10);
}
}).ContinueWith(t=>{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(() =>
{
if (_similaritySearchResults != null && _similaritySearchResults.Tables["data"].Rows.Count > 0)
{
DataTable dt = _similaritySearchResults.Tables["data"];
Infragistics.Win.Misc.UltraTile newTile = null;
for (int index = 0; index < dt.Rows.Count; index++)
{
newTile = new Infragistics.Win.Misc.UltraTile("Person X");
newTile.Control = new CustomControls.Controls.PersonResult("123", "123", index + 150);
newTile.Tag = new Guid("90D27721-7315-4B86-9CFD-4F7D02921E9A");
newTile.DoubleClick += TileDoubleClick;
tilePanel.Tiles.Add(newTile);
}
}
}));
}
else
{
if (_similaritySearchResults != null && _similaritySearchResults.Tables["data"].Rows.Count > 0)
{
DataTable dt = _similaritySearchResults.Tables["data"];
Infragistics.Win.Misc.UltraTile newTile = null;
for (int index = 0; index < dt.Rows.Count; index++)
{
newTile = new Infragistics.Win.Misc.UltraTile("Person X");
newTile.Control = new CustomControls.Controls.PersonResult("123", "123", index + 150);
newTile.Tag = new Guid("90D27721-7315-4B86-9CFD-4F7D02921E9A");
newTile.DoubleClick += TileDoubleClick;
tilePanel.Tiles.Add(newTile);
}
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
これは正常に動作しています。アプリケーションはデータベースに移動し、結果を取得して UI を更新し、データベースから返されたレコードの数に応じてタイルをコントロールに追加します。
ここで、カスタム コントロールに別のバックグラウンド スレッドを追加しようとすると問題が発生します。
new CustomControls.Controls.PersonResult("123", "123", インデックス + 150);
コントロールのコードは次のとおりです。
protected override void InitLayout()
{
// if I comment this then everything works fine
// but if I leave this, then the UI freezes!!
GetPictureAsync();
base.InitLayout();
}
/// <summary>
///
/// </summary>
private void GetPictureAsync()
{
// This line needs to happen on the UI thread...
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
Random sleep = new Random();
System.Threading.Thread.Sleep(sleep.Next(1000,3000));
if (this.pbPhoto.InvokeRequired)
{
this.pbPhoto.Invoke(new Action(() =>
{
this.Load(@"E:\Photos\" + PhotoId.ToString() + ".jpg");
//this.pbPhoto.Image = Utility.Common.GetResourceImage("woman_sample.jpg");
}));
}
else
{
this.Load(@"E:\Photos\" + PhotoId.ToString() + ".jpg");
//this.pbPhoto.Image = Utility.Common.GetResourceImage("woman_sample.jpg");
}
}, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}
問題は、検索を開始するタイミングを確認するために最初にスレッドを実行し、次にそのスレッド内でデータベースからデータを取得するために別のスレッドを実行し、UI で更新された各コントロールが別のスレッドを実行して取得することです。ピクチャボックスを更新します。
誰でもこれを解決する方法を知っていますか? またはこれを回避する方法はありますか?