使用线程显示Windows窗体 [英] displaying a windows form using threads

查看:61
本文介绍了使用线程显示Windows窗体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

在Visual Studio 2005中使用VB.Net.

就我而言,这有点棘手.

我正在尝试向用户显示一个已拆分的表单-左侧显示了一个多页tif,分隔到TabPage上(标签页= tif中的页数).

在表单启动画面上,我有许多查询要执行,以在屏幕右侧显示与tif相关的相应数据.

进行此操作的第一个尝试不是使用线程,该表单可能需要相当长的时间才能完全显示在屏幕上(有时需要25秒).

我现在想做的是将tif的显示和查询放到线程中,以便可以同时进行操作.这些查询可能需要一段时间才能返回(在某些情况下,每次查询可能需要一到两次).

我认为这是一个好主意,唯一的问题是,每当代码需要使用一些新数据更新表单时(即,填充了TextBox),我都需要调用一个在主线程上执行此操作的函数.

然后,我结束了多个线程的运行(这不是问题),并且每个线程都在争先恐后地将数据显示到屏幕上.表单可以更快地显示出来,但是由于线程仍然在表单更新的下面发生,因此它真的还没准备好使用,直到一切都完成了.

不知道以前是否有人遇到过这种情况,并且可以帮助您找到最好的解决方法吗?

希望我已经让自己足够清楚,并且有人知道.

朱利安

Hi All,

Using VB.Net in Visual Studio 2005.

Bit of a tricky one as far as I''m concernend this.

I''m trying to display a Form to the user that is split - the left side shows a multipage tif, separated onto a TabPage (tab pages = no. pages in tif).

On form starup I have a number of queries to perform to show corresponding data relating to the tif on the right of the screen.

The first attempt at doing all this wasn''t using threads, and the form could take quite a while to display fully to the screen (sometimes 25 seconds).

What I am now trying to do is put the display of the tif and the queries into threads so that things can be done concurrently. The queries can take quite a while to come back (a second or two each in some cases).

A good idea I thought, the only problem being that whenver the code needs to update the form with some new data (i.e. a TextBox is populated) I need to call a function that does this on the main thread.

I then end up with multiple threads going on (not a problem) and each of those threads fighting to display data to the screen. The form can appear quicker, but with threads still happening underneath with form updates, it''s really not ready for use until again, everything has finished.

Don''t know if anyone has encountered this scenario before and could help with the best way forward?

Hope I''ve made myself clear enough and that someone has an idea.

Julian

推荐答案

如果我正确理解您的意思,您正在运行多个查询以填充1个屏幕.

在这种情况下,将查询组织到服务器上的一个存储过程中.这将减少流量,因为您仅将必需的参数传递给proc并接收所需的最终数据集,从而加快了处理速度.

根据proc运行的复杂性和时间,您可能需要在显示tif时使用backgroung worker来处理数据.
If I understand you correctly you are running multiple queries to populate 1 screen.

If this is the case, organise your queries into one stored procedure on your server. This will reduce traffic as you only pass necessary parameters to the proc and receive the final dataset required, therefore speeding up your process.

Depending on the complexity and time for the proc to run you might need to use backgroung worker for the data while you display the tif.




您可以使用回调委托来回调主线程方法.使用委托将方法指针传递给线程.使用委托进行回叫.使用方法调用程序(再次使用委托)在主线程中更新文本控件.

例如,我有两个图片框和两个文本框.当我单击一个按钮时,我通过2个线程加载了两个图片框,并回调了更新文本框方法,如下所示.您也可以在线程的位置使用后台工作器.

Hi,

You can call back to a main thread method using a call back delegate. Pass the methods pointer using a delegate to the thread. Call back using the delegate. For updating text controls in the main thread using method invoker (which again use a delegate).

As a example say I have 2 picture box and two text box. when I click a button i load the two picture box through 2 threads and callback the update text box methods as shown below. You can use background worker in the place of threads as well.

public partial class Form1 : Form
{
    private  delegate void TextboxPopulate(string txt);

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        //Delegate of the method to call back from the thread
        TextboxPopulate del1 = new TextboxPopulate(populateTextBox1Invoker);
        //pass the delegate as a parameter
        ParameterizedThreadStart threadStart1 = new ParameterizedThreadStart(LoadPictureBox1);
        Thread thread1 = new Thread(threadStart1);
        thread1.Start(del1);


        TextboxPopulate del2 = new TextboxPopulate(populateTextBox2Invoker);
        ParameterizedThreadStart threadStart2 = new ParameterizedThreadStart(LoadPictureBox2);
        Thread thread2 = new Thread(threadStart2);
        thread2.Start(del2);
    }

    private void LoadPictureBox1(object textBoxPolpulateDelegate)
    {
        //do its work and call the callback method in the main thread
        pictureBox1.Image = new Bitmap("Flower1.jpg");
        object[] args=new object[1];
        args[0]="Rose";
        Delegate del1 = (Delegate)textBoxPolpulateDelegate;
        del1.DynamicInvoke(args);

        //This still works, but using a delegate is better option
        //populateTextBox1Invoker("Rose");
    }
    private void LoadPictureBox2(object textBoxPolpulateDelegate)
    {
        pictureBox2.Image = new Bitmap("Flower2.jpg");
        object[] args = new object[1];
        args[0] = "Tulip";
        Delegate del1 = (Delegate)textBoxPolpulateDelegate;
        del1.DynamicInvoke(args);

        //This still works, but using a delegate is better option
        //populateTextBox2Invoker("Tulip");

    }

    private void populateTextBox1Invoker(string txt)
    {
       //Handle the cross thread operation
        if (textBox1.InvokeRequired == true)
        {
            this.Invoke((MethodInvoker)delegate
            {
                textBox1.Text = txt;
            });

        }
        else
        {
            textBox1.Text = txt;
        }
    }

    private void populateTextBox2Invoker(string txt)
    {
        //Handle the cross thread operation
        if (textBox2.InvokeRequired == true)
        {

            this.Invoke((MethodInvoker)delegate
            {
                textBox2.Text =txt;
            });

        }
        else
        {
            textBox2.Text = txt;
        }
    }

}



或者,您可以将所有查询放入异步调用中,当执行查询时,您可以继续异步加载图像.加载图像后,查询也可能会完成并准备显示.

一个异步示例....

在上面的示例中添加一个按钮,并在顶部具有委托声明(对于form/form实例变量是全局的)



Alternatively you can put all the queries in a async call, when the queries executing you can continue loading the images asynchronously. Once the images loaded you the queries also might be finished and ready to display.

An asynchronous example....

add a button to the above example and have delegate declaration at the top (global to form/ form instance variable)

private delegate string QueryDelegate();



说说这个委托来说明一个忙碌方法的例子,最后它返回一个字符串.

忙碌的方法...



say this delegate for an example busy method and finally it returns a string.

the busy method...

private string  myQueryProcess()
 {
     for (int i = 0; i < 5; i++)
     {
         Thread.Sleep(1000);
     }
     return "Query Completed";
 }




现在在按钮单击事件中...




now in the button click event...

private void button2_Click(object sender, EventArgs e)
{
    QueryDelegate del1 = new QueryDelegate(myQueryProcess);
    IAsyncResult result= del1.BeginInvoke(null,null);
    pictureBox1.Image = new Bitmap("Flower1.jpg");
    pictureBox2.Image = new Bitmap("Flower2.jpg");
    string resultStr=del1.EndInvoke(result);
    MessageBox.Show(resultStr);

}



您可以看到图像将被加载,而无需等待忙碌方法完成.忙碌的方法将在5秒钟后结束.



you can see the images will be loaded without waiting for the busy method to be finished. the busy method will finish after 5 seconds.


您可以使用主过程最初加载所有数据,然后使用lamda调用填充数据作为线程运行它

You could use a main procedure to load all the data initially, and run that as a thread, using lamda invokation to populate the data

<br />
<pre lang="C#">public partial class frmMain : Form<br />
    {<br />
        public frmMain()<br />
        {<br />
            InitializeComponent();<br />
            PopulateData();<br />
        }<br />
<br />
        private bool frmLoaded<br />
        {//disable or enable the form based on the data load<br />
            get { return this.Enabled; }<br />
            set { this.Enabled = value; }<br />
        }<br />
<br />
        private void PopulateData()<br />
        {<br />
            System.Threading.Thread T = new System.Threading.Thread(new System.Threading.ThreadStart(PopulateDateThread));<br />
            T.IsBackground = true;<br />
            T.Start();<br />
            frmLoaded = false;<br />
        }<br />
        private void PopulateDateThread()<br />
        {<br />
            Image im1 = Database.GetImagefromDB();<br />
            Image im2 = Database.GetImagefromDB();<br />
            Image im3 = Database.GetImagefromDB();<br />
<br />
            pictureBox1.Invoke(new Action<Image>((I) => pictureBox1.Image = I), new object[]{im1});<br />
            pictureBox2.Invoke(new Action<Image>((I) => pictureBox2.Image = I), new object[]{im1});<br />
            pictureBox3.Invoke(new Action<Image>((I) => pictureBox3.Image = I), new object[]{im1});<br />
            this.Invoke(new Action<bool>((b) => this.frmLoaded = b), new object[] { true });<br />
        }<br />
<br />
    }</pre>


这篇关于使用线程显示Windows窗体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆