Thread.Sleep冻结UI

时间:2014-10-24 07:47:11

标签: c# wpf multithreading

我知道,它已多次来过这里,但我仍然不知道该怎么做。

我想创建一个程序,它将重复从数据库下载数据,因此用户将在此时看到程序中的数据。

我不需要快速加载数据库,所以我使用sleep,但是整个UI会睡眠冻结。

我举一个简单的例子。

<Window x:Class="ThreadingPrimeNumberSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Prime Numbers" Width="760" Height="500">
    <Grid>
        <Button Content="Start"  
            Click="StartOrStop"
            x:Name="startStopButton"
            Margin="10,10,693,433"
            />
        <TextBlock Margin="87,15,547,424"><Run Text="Biggest Prime Found:"/><InlineUIContainer>

            </InlineUIContainer></TextBlock>
        <TextBlock x:Name="bigPrime" Margin="222,15,409,428"><Run Text="3"/></TextBlock>
        <TextBox Height="104" TextWrapping="Wrap" Text="TextBox" Width="522" Margin="87,295,143,70"/>
    </Grid>
</Window>


...usings...

namespace ThreadingPrimeNumberSample
{

    public partial class MainWindow : Window
    {
        public delegate void NextPrimeDelegate();

        //Current number to check 

        private long num = 3;

        private bool continueCalculating = false;

        public MainWindow()
            : base()
        {
            InitializeComponent();
        }

        private void StartOrStop(object sender, EventArgs e)
        {
            if (continueCalculating)
            {
                continueCalculating = false;
                startStopButton.Content = "Resume";
            }
            else
            {
                continueCalculating = true;
                startStopButton.Content = "Stop";
                startStopButton.Dispatcher.BeginInvoke(
                    DispatcherPriority.Normal,
                    new NextPrimeDelegate(CheckNextNumber));
            }
        }


        public void CheckNextNumber()
        {

            // Reset flag.
            NotAPrime = false;

            for (long i = 3; i <= Math.Sqrt(num); i++)
            {
                if (num % i == 0)
                {
                    // Set not a prime flag to true.
                    NotAPrime = true;
                    break;
                }
            }

            // If a prime number.
            if (!NotAPrime)
            {
                bigPrime.Text = num.ToString();
            }

            num += 2;

            Thread.Sleep(500);



            if (continueCalculating)
            {
                startStopButton.Dispatcher.BeginInvoke(
                    System.Windows.Threading.DispatcherPriority.SystemIdle,
                    new NextPrimeDelegate(this.CheckNextNumber));
            }
        }


        private bool NotAPrime = false;


        }


    }

如果过程已开始,我写入文本框或做某事......整个过程就冻结了。

这段代码应该如何运行并且UI不会被冻结?

4 个答案:

答案 0 :(得分:4)

要定期执行某些操作,您应该使用计时器。如果你想要一个在WPF UI线程上触发的计时器,请使用DispatcherTimer - 尽管你正在下载数据的事实表明你要么是异步地执行,要么是使用后台线程。对于后者,您可以使用System.Threading.Timer

基本上你应该从不阻止UI线程很长一段时间,正是因为它会冻结你的UI。

答案 1 :(得分:1)

调用startStopButton.Dispatcher.BeginInvoke表示它将在UI线程上运行。这确实意味着在调用该方法时,您的UI会冻结,其中包含Thread.Sleep

我建议创建一个新的Task并在那里执行您的代码。在与UI元素交互时,您需要调用InvokeBeginInvoke,以防止跨线程UI操作。

Task.Run(CheckNextNumber);

答案 2 :(得分:1)

不冻结UI,您可以使用许多工具:

如果您犹豫不决,可以阅读C# / VB.Net Task vs Thread vs BackgroundWorker

答案 3 :(得分:0)

我拥有它:

newtheard(); // This start new theard with loading form database   

    public void newtheard()
        {
            Thread thread = new Thread(new ThreadStart(this.ReadFromMysql);
            thread.IsBackground = true;
            thread.Name = "My Worker.";
            thread.Start();
        }

        public void ReadFromMysql()
            {
                while (true)
                {
                    Thread.Sleep(800);
                    try
                    {
                          // some mysql reader
                    }
                }