WPF加载大量控件的优化

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

猜你喜欢

转载自blog.csdn.net/sinat_31608641/article/details/107257677