我知道,它已多次来过这里,但我仍然不知道该怎么做。
我想创建一个程序,它将重复从数据库下载数据,因此用户将在此时看到程序中的数据。
我不需要快速加载数据库,所以我使用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不会被冻结?
答案 0 :(得分:4)
要定期执行某些操作,您应该使用计时器。如果你想要一个在WPF UI线程上触发的计时器,请使用DispatcherTimer
- 尽管你正在下载数据的事实表明你要么是异步地执行,要么是使用后台线程。对于后者,您可以使用System.Threading.Timer
。
基本上你应该从不阻止UI线程很长一段时间,正是因为它会冻结你的UI。
答案 1 :(得分:1)
调用startStopButton.Dispatcher.BeginInvoke
表示它将在UI线程上运行。这确实意味着在调用该方法时,您的UI会冻结,其中包含Thread.Sleep
。
我建议创建一个新的Task
并在那里执行您的代码。在与UI元素交互时,您需要调用Invoke
或BeginInvoke
,以防止跨线程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
}
}