线程.睡眠冻结UI
本文关键字:UI 冻结 线程 | 更新日期: 2023-09-27 18:27:44
我知道,它在这里已经很多次了,但我仍然不知道如何做到。
我想创建一个程序,重复从数据库下载数据,这样用户就可以在这个时候看到程序中的数据。
我不需要快速加载数据库,所以我使用睡眠,但睡眠冻结了整个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不会被冻结?
要定期执行某些操作,应该使用计时器。如果您想要一个在WPF UI线程上触发的计时器,请使用DispatcherTimer
——尽管下载数据的事实表明您应该异步执行,或者使用后台线程。对于后者,可以使用System.Threading.Timer
。
基本上,您应该永远不要在相当长的一段时间内阻塞UI线程,正是因为它会冻结您的UI。
调用startStopButton.Dispatcher.BeginInvoke
意味着它将在UI线程上运行。这确实意味着您的UI在调用该方法时会冻结,其中包含Thread.Sleep
我建议创建一个新的Task
并在其中执行您的代码。不过,在与UI元素交互时,您需要调用Invoke
或BeginInvoke
,以防止跨线程的UI操作。
Task.Run(CheckNextNumber);
为了不冻结UI,可以使用许多工具:
- 线程:http://msdn.microsoft.com/en-us/library/7a2f3ay4(v=vs.90).aspx
- 具有async和wait的任务:http://msdn.microsoft.com/en-us/library/dd537609(v=vs.110).aspx
- BackgroundWorker:如何使用WPF后台工作程序
如果您有犹豫,可以阅读C#/VB.Net任务与线程与BackgroundWorker。
我有它:
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
}
}