WPF 应用程序从两个线程开始:一个用于处理呈现,一个用于管理 UI。呈现线程有效地隐藏在后台运行,而 UI 线程则接收输入、处理事件、绘制屏幕以及运行应用程序代码。
UI 线程对一个名为 Dispatcher 的对象内的工作项进行排队。Dispatcher 基于优先级选择工作项,并运行每一个工作项,直到完成。每个 UI 线程都必须至少有一个 Dispatcher,并且每个 Dispatcher 都只能在一个线程中执行工作项。 而我们使用的基本上都是管理UI的线程,Dispatcher。
问题
假如我们的程序只有一个线程处理UI,当UI需要渲染很多的控件时,界面就会出现假死的现象,这个时候就需要一个缓冲控件显示,直到UI渲染完成,可以继续接受输入,处理事件。
那么问题来了,如果这个缓冲动画和主UI用的同一个Dispatcher,你的缓冲控件的动画也会假死。
如何处理呢?
方案
1.将线程设置为应用程序空闲处理
Dispatcher.BeginInvoke(new Action(() =>
{
加载控件;
}), System.Windows.Threading.DispatcherPriority.ApplicationIdle);
2.提示等待框
在新线程中启动等待框
http://blog.csdn.net/steel_1991/article/details/54428525
3.启用虚拟化
VirtualizingStackPanel
实例
XAML
<Window x:Class="WpfApplication69.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525"
Loaded="Window_Loaded">
<Window.Resources>
<Storyboard x:Key="sb1">
<DoubleAnimation Storyboard.TargetName="rectangle"
Storyboard.TargetProperty="(TextBlock.RenderTransform).(RotateTransform.Angle)"
From="0"
To="360"
Duration="0:0:1"
RepeatBehavior="Forever" />
</Storyboard>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle Name="rectangle"
Width="20"
Height="20"
Fill="Blue"
Margin="5"
VerticalAlignment="Center">
<Rectangle.RenderTransform>
<RotateTransform Angle="0"
CenterX="10"
CenterY="10" />
</Rectangle.RenderTransform>
</Rectangle>
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid x:Name="gg">
</Grid>
</ScrollViewer>
</Grid>
</Window>
C#
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ShowWnd();
}
private void ShowWnd()
{
Storyboard sb = (Storyboard)this.Resources["sb1"];
sb.Begin(rectangle,true);
Action a0 = NewMethod;
Action a1 = NewMethod1;
Action<int, int> a2 = NewMethod2;
Action a = new Action(() =>
{
int count = 200;
for (int i = 0; i < count; i++)
{
this.Dispatcher.BeginInvoke(a1,DispatcherPriority.Background);
for (int j = 0; j < 250; j++)
{
if (i == 0)
{
this.Dispatcher.BeginInvoke(a0, DispatcherPriority.Background);
}
this.Dispatcher.BeginInvoke( DispatcherPriority.Background,a2, i, j);
System.Threading.Thread.Sleep(1);
}
}
});
AsyncCallback callBack = new AsyncCallback((aa) =>
{
Action stop = new Action(() =>
{
sb.Stop(rectangle);
});
this.Dispatcher.Invoke(stop);
});
a.BeginInvoke(callBack, null);
//Task t = Task.Factory.StartNew(a);
//Action<Task> cont = new Action<Task>((tt) =>
//{
// this.Background = Brushes.Yellow;
//});
//t.ContinueWith(cont);
}
private void NewMethod2(int i, int j)
{
Border bd = new Border();
bd.BorderBrush = Brushes.Black;
bd.BorderThickness = new Thickness(0.5);
bd.Background = Brushes.Yellow;
Grid.SetColumn(bd, j);
Grid.SetRow(bd, i);
gg.Children.Add(bd);
}
private void NewMethod1()
{
gg.RowDefinitions.Add(
new RowDefinition()
{
Height = new GridLength(5, GridUnitType.Pixel)
}
);
}
private void NewMethod()
{
gg.ColumnDefinitions.Add(
new ColumnDefinition()
{
Width = new GridLength(5, GridUnitType.Pixel)
}
);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// ShowWnd();
}
参考:
https://blog.csdn.net/steel_1991/article/details/54428525
https://blog.csdn.net/weixin_30707875/article/details/98324669
https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/advanced/threading-model?redirectedfrom=MSDN