none
使用Frame动态加载XAML慢的问题 RRS feed

  • 问题

  • 近日在开发过程中遇到动态加载XAML页面过慢的问题,不知道如何解决,希望各位兄弟能帮忙看看。
    具体问题如下:
    在程序运行过程中(如:选择的ListItem发生变化时),使用下记方式想完成新Page的载入
    Frame NextFrame.Source = new Uri(new Uri("pack://application:,,,/"), "Views/SettingsPage.xaml");
    grid.Children.Add(NextFrame);

    经过Debug信息确认,从上面的语句开始,到SettingsPage.xaml.cs中的构造函数被调用共计花费了750ms的时间
    从程序运行效果看,明显能够感觉到此操作过程中有些卡,不知道该如何优化。

    期待高手们能给指点指点,谢谢。
    2011年4月12日 7:58

答案

  • CLR中对于一个方法的最终执行前,或者说中间代码要被执行,都会去调用JIT去在运行时编译的。我所未得加载,其实就是让你的程序集的中间代码能够得到一次在使用前的预编译,通常叫做pre-JIT。这篇文章就介绍了怎么去做这个预编译:http://www.codeproject.com/KB/dotnet/pre_JIT.aspx,通过Assembly.Load方法先将程序集load到你的AppDomain中,然后遍历素有类型的方法,将其通过JIT编译一边,被缓存后,在下次使用的时候就可以提高很多效率。

    Jeffrey的CLR Via C#这本书中的第一章 1.4 节就讲到了CLR是怎么执行代码的,你可以参阅下。

     

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 YinRuifeng 2011年4月13日 9:23
    2011年4月13日 5:42
    版主

全部回复

  • 如果你可以直接实例化SettingPage实例的话,建议直接调用 Frame.NavigationSerivce.Navigate()到这个实例,会快一点。

    还有,提供点完整的代码吧,这样我们也能帮你看看,否则真的无法还原这个场景。

     

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年4月12日 14:28
    版主
  • 按照版主的要求,追加部分代码实现,希望大家能够再现。

    ■待加载页面代码

    ※其中使用了Telerik的第三方控件,经过本人分析,第一次加载页面时(耗时750ms现象发生时,需要载入如下几个dll文件:

    1.Telerik.Windows.Controls.Navigation.dll

    2.Telerik.Windows.Controls.dll

    3.Telerik.Windows.Controls.GridView.dll

    4.Telerik.Windows.Data.dll

    5.Telerik.Windows.Controls.Input.dll

    问题应该就在这里了,希望版主能指出问题所在)

     

    下面给出加载页面完整代码如下:

    <local:BasePage x:Class="iTouch_MVVM.Views.SettingsPage"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:iTouch_MVVM.Views" 

        xmlns:my="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView"

        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">

        <Grid>

            <Grid.RowDefinitions>

                <RowDefinition Height="215" />

                <RowDefinition Height="10" />

                <RowDefinition Height="215" />

            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="275" />

                <ColumnDefinition Width="5" />

                <ColumnDefinition Width="575" />

            </Grid.ColumnDefinitions>

            <Border  Grid.Row="0" Grid.Column="0" Grid.RowSpan="3"  CornerRadius="3" BorderThickness="1" BorderBrush="LightGray" RenderOptions.EdgeMode="Aliased">

                <my:RadGridView Name="radGridView1" CanUserFreezeColumns="False" SnapsToDevicePixels="True" BorderThickness="2" BorderBrush="LightGray" 

                                CanUserResizeColumns="False" ShowGroupPanel="False" AutoGenerateColumns="False" Focusable="False" Margin="0" 

                                RowEditEnded="radGridView1_RowEditEnded" SelectionChanged="radGridView1_SelectionChanged">

                    <telerik:RadContextMenu.ContextMenu>

                        <telerik:RadContextMenu Opened="RadContextMenu_Opened" ItemClick="RadContextMenu_ItemClick">

                            <telerik:RadContextMenu.Items>

                                <telerik:RadMenuItem Header="Add"/>

                                <telerik:RadMenuItem Header="Delete"/>

                            </telerik:RadContextMenu.Items>

                        </telerik:RadContextMenu>

                    </telerik:RadContextMenu.ContextMenu>

                    <my:RadGridView.Columns>

                        <my:GridViewDataColumn Header="Reg" Width="54" DataMemberBinding="{Binding RegisterName}" Focusable="False"/>

                        <my:GridViewDataColumn Header="Port" Width="52" DataMemberBinding="{Binding PortsName}" Focusable="False"/>

                        <my:GridViewDataColumn Header="Func" Width="60" DataMemberBinding="{Binding FuncType}" Focusable="False">

                            <my:GridViewColumn.CellTemplate>

                                <DataTemplate>

                                    <telerik:RadComboBox ItemsSource="{Binding FuncList}" SelectedValue="{Binding FuncType}" Focusable="False"/>

                                </DataTemplate>

                            </my:GridViewColumn.CellTemplate>

                        </my:GridViewDataColumn>

                        <my:GridViewDataColumn Header="Init" Width="30" DataMemberBinding="{Binding InitValue}" IsFilterable="False" Focusable="False"/>

                        <my:GridViewDataColumn Header="Opt" Width="30" DataMemberBinding="{Binding CheckedState}" IsFilterable="False" Focusable="False">

                            <my:GridViewColumn.CellTemplate>

                                <DataTemplate>

                                    <CheckBox IsChecked="{Binding CheckedState}" IsEnabled="False" Focusable="False" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True"/>

                                </DataTemplate>

                            </my:GridViewColumn.CellTemplate>

                            <my:GridViewColumn.CellEditTemplate>

                                <DataTemplate>

                                    <CheckBox IsChecked="{Binding CheckedState}" Checked="CheckBox_Checked" HorizontalAlignment="Center" VerticalAlignment="Center"/>

                                </DataTemplate>

                            </my:GridViewColumn.CellEditTemplate>

                        </my:GridViewDataColumn>

                    </my:RadGridView.Columns>

                </my:RadGridView>

            </Border>

            <Border Grid.Row="0" Grid.Column="2" Background="{StaticResource MyGrayGridBrushResource}" CornerRadius="3" BorderThickness="2"

                    BorderBrush="LightGray" Margin="0,2,5,0" SnapsToDevicePixels="True" MouseMove="Canvas_MouseMove" Name="border_standbyout"

                    MouseLeftButtonDown="border_standbyout_MouseLeftButtonDown" MouseRightButtonDown="border_standbyout_MouseRightButtonDown">

                <Canvas Name="canvas_standbyout">

                    <Label Name="watch" Width="150" Height="30" Canvas.Top="11" Canvas.Left="400" FontFamily="Verdana" FontSize="14">∆Time =</Label>

                    <Label Content="ACC" FontSize="8" Height="22" Canvas.Top="51" Canvas.Left="24" Width="80" Foreground="DarkGray" />

                    <!--Low Line-->

                    <Path StrokeThickness="2" Stroke="DarkGray" Data="M 52,0 L80,0" Canvas.Top="70"/>

                    <!--Connect Line-->

                    <Path StrokeThickness="2" Stroke="DarkGray" Data="M 80,0 l0,20" Canvas.Top="50"/>

                    <!--High Line-->

                    <Path StrokeThickness="2" Stroke="DarkGray" Data="M 80,0 L550,0" Canvas.Top="50"/>

     

                    <!--Symbol Line-->

                    <Path Stroke="Red" StrokeThickness="1" Name="symbl_line" Panel.ZIndex="99">

                        <Path.Data>

                            <PathGeometry>

                                <PathFigure StartPoint="75,40" IsClosed="False">

                                    <LineSegment Point="80,45"/>

                                </PathFigure>

                                <PathFigure StartPoint="85,40" IsClosed="False">

                                    <LineSegment Point="80,45"/>

                                </PathFigure>

                                <PathFigure StartPoint="80,45" IsClosed="False">

                                    <LineSegment Point="80,205"/>

                                </PathFigure>

                            </PathGeometry>

                        </Path.Data>

                    </Path>

                    <!--Target Line-->

                    <Path StrokeThickness="4" Stroke="DarkGreen" Opacity="0.2" Visibility="Hidden" Name="port_path" Data="M 52,100 L550,100" Canvas.Top="50"/>

                    <!--Setting Point-->

                    <Ellipse Panel.ZIndex="100" Width="8" Height="8" Name="SettingPoint" Fill="Green" Visibility="Hidden" Canvas.Top="145" MouseLeftButtonDown="SettingPoint_MouseLeftButtonDown"/>

                    <!--Y-axis-->

                    <Path StrokeThickness="3" Stroke="Black" Data="M 50,0 L50,165" Canvas.Top="30"/>

                    <!--X-axis-->

                    <Path StrokeThickness="3" Stroke="Black" Data="M 50,0 L550,0" Canvas.Top="194"/>

                </Canvas>

            </Border>

            <Border Grid.Row="3" Grid.Column="2" Background="{StaticResource MyGrayGridBrushResource}" CornerRadius="3" BorderThickness="2"

                    BorderBrush="LightGray" Margin="0,2,5,0" SnapsToDevicePixels="True" Name="border_standbyin" MouseMove="Canvas_MouseMove">

                <Canvas Name="canvas_standbyin">

                    <!--Y-axis-->

                    <Path StrokeThickness="3" Stroke="Black" Data="M 50,0 L50,165" Canvas.Top="30"/>

                    <!--X-axis-->

                    <Path StrokeThickness="3" Stroke="Black" Data="M 50,0 L550,0" Canvas.Top="194"/>

                    <Label Content="StandbyIn完成通知" FontSize="8" Height="22" Canvas.Top="33" Canvas.Left="51" Width="80" Foreground="DarkGray" />

                    <!--Low Line-->

                    <Path StrokeThickness="2" Stroke="DarkGray" Data="M 52,0 L80,0" Canvas.Top="50"/>

                    <!--Connect Line-->

                    <Path StrokeThickness="2" Stroke="DarkGray" Data="M 80,0 l0,20" Canvas.Top="50"/>

                    <!--High Line-->

                    <Path StrokeThickness="2" Stroke="DarkGray" Data="M 80,0 L550,0" Canvas.Top="70"/>

                </Canvas>

            </Border>

        </Grid>

    </local:BasePage>

    2011年4月12日 15:02
  • 这个问题就很尴尬了,你使用了第三方的库,而你的初步分析是正确的,在载入这些库的时候是需要大量的时间的。但是,第三方的库,微软是无法帮你测试的。所以你可能需要一点比较通用的解决方案,比如预先载入这几个库,比如参考MSDN关于优化WPF性能的文档来优化你的文档内容,因为有一部分的性能损失其实是发生在你的比较复杂的文档内容中:优化 WPF 应用程序性能

    还有,你还需要去下载WPF Performence Tool来帮助你来测试和观察性能。

    不过,最后,我还是很建议你去联系Telerik 技术支持,咨询下他们有没有好的方案来解决加载他们的程序集满的问题,谢谢。Telerik 技术支持论坛: http://www.telerik.com/community/forums.aspx

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年4月12日 15:51
    版主
  • 这个问题就很尴尬了,你使用了第三方的库,而你的初步分析是正确的,在载入这些库的时候是需要大量的时间的。但是,第三方的库,微软是无法帮你测试的。所以你可能需要一点比较通用的解决方案,比如预先载入这几个库,比如参考MSDN关于优化WPF性能的文档来优化你的文档内容,因为有一部分的性能损失其实是发生在你的比较复杂的文档内容中:优化 WPF 应用程序性能

    还有,你还需要去下载WPF Performence Tool来帮助你来测试和观察性能。

    不过,最后,我还是很建议你去联系Telerik 技术支持,咨询下他们有没有好的方案来解决加载他们的程序集满的问题,谢谢。Telerik 技术支持论坛: http://www.telerik.com/community/forums.aspx

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.



    感谢版主的回复,关于上面所说的“预先加载这几个库”应该怎么做呢?能否给出个例子?
    2011年4月13日 2:18
  • CLR中对于一个方法的最终执行前,或者说中间代码要被执行,都会去调用JIT去在运行时编译的。我所未得加载,其实就是让你的程序集的中间代码能够得到一次在使用前的预编译,通常叫做pre-JIT。这篇文章就介绍了怎么去做这个预编译:http://www.codeproject.com/KB/dotnet/pre_JIT.aspx,通过Assembly.Load方法先将程序集load到你的AppDomain中,然后遍历素有类型的方法,将其通过JIT编译一边,被缓存后,在下次使用的时候就可以提高很多效率。

    Jeffrey的CLR Via C#这本书中的第一章 1.4 节就讲到了CLR是怎么执行代码的,你可以参阅下。

     

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 YinRuifeng 2011年4月13日 9:23
    2011年4月13日 5:42
    版主
  • CLR中对于一个方法的最终执行前,或者说中间代码要被执行,都会去调用JIT去在运行时编译的。我所未得加载,其实就是让你的程序集的中间代码能够得到一次在使用前的预编译,通常叫做pre-JIT。这篇文章就介绍了怎么去做这个预编译:http://www.codeproject.com/KB/dotnet/pre_JIT.aspx,通过Assembly.Load方法先将程序集load到你的AppDomain中,然后遍历素有类型的方法,将其通过JIT编译一边,被缓存后,在下次使用的时候就可以提高很多效率。

    Jeffrey的CLR Via C#这本书中的第一章 1.4 节就讲到了CLR是怎么执行代码的,你可以参阅下。

     

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.



    感谢版主的帮助!
    2011年4月13日 9:21