1

我在带有文本框的 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", index + 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 中更新的每个控件将运行另一个线程来获取图片并更新图片框。

任何人都知道如何解决这个问题?或解决此问题的方法?

4

2 回答 2

0

你打电话时

new CustomControls.Controls.PersonResult("123", "123", index + 150)

“123”是文字字符串,还是从 UI 控件中读取的。例如,

new CustomControls.Controls.PersonResult(txtFathersName.Text", txtMothersName.Text, index + 150)

我现在无法对其进行测试,但是是否不允许从创建控件的线程以外的线程访问 Text 属性?

于 2013-10-05T16:54:30.067 回答
0

我认为问题在于你强制任务在GetPictureAsyncUI 线程上执行,然后你正在调用Thread.Sleep(). 使用 TaskScheduler.FromCurrentSynchronizationContext 问题的 Task 中的此更新 UI解决了与您遇到的相同问题。我会将您的代码重写为:

private void async GetPictureAsync()
{
    Random sleep = new Random();
    await TaskEx.Delay(sleep.Next(1000,3000));
    this.Load(@"E:\Photos\" + PhotoId.ToString() + ".jpg");
}
于 2013-10-05T20:59:17.933 回答