【问题标题】:Thread.Sleep freeze the UIThread.Sleep 冻​​结 UI
【发布时间】:2020-11-05 14:53:24
【问题描述】:

我知道,已经来过很多次了,但我还是不知道该怎么做。

我想创建一个程序,会重复从数据库中下载数据,所以用户会看到程序中的数据到这个时候。

我不需要快速加载数据库,所以我使用睡眠,但睡眠冻结整个 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 不会被冻结?

【问题讨论】:

    标签: c# wpf multithreading


    【解决方案1】:

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

    基本上你应该永远长时间阻塞 UI 线程,因为它会冻结你的 UI。

    【讨论】:

      【解决方案2】:

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

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

      Task.Run(CheckNextNumber);
      

      【讨论】:

        【解决方案3】:

        不要冻结 UI,你可以使用很多工具:

        如有犹豫,可以阅读C# / VB.Net Task vs Thread vs BackgroundWorker

        【讨论】:

          【解决方案4】:

          我有:

          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
                              }
                          } 
          

          【讨论】:

            猜你喜欢
            • 2014-07-30
            • 2022-11-14
            • 1970-01-01
            • 1970-01-01
            • 2014-12-22
            • 2011-12-10
            • 1970-01-01
            相关资源
            最近更新 更多