【问题标题】:Rendering ListBox takes too long on Windows Phone在 Windows Phone 上渲染 ListBox 花费的时间太长
【发布时间】:2015-01-14 05:03:50
【问题描述】:

我正在使用本地 SQLite 数据库开发 Windows Phone 7 应用程序,但我遇到了使用 DataBinding 的页面呈现时间问题。

目前从数据库中检索数据需要 60-70 毫秒。然后渲染使用带有 DataBinding 的 ListBox 检索到的数据大约需要 3100 毫秒。

这里可以看到ListBox的DataTemplate:

<DataTemplate x:Key="ListBoxItemTemplate">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="68" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <TextBlock x:Name="TimeColumn"
                        Text="{Binding TimeSpan}" Grid.Column="0" Grid.Row="0"
                        Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <TextBlock Text="{Binding Stop.StopName}" Grid.Column="1" Grid.Row="0" 
                                Margin="15,0,0,0" TextWrapping="NoWrap" Foreground="Black"
                                HorizontalAlignment="Left" VerticalAlignment="Center" />
    </Grid>
 </DataTemplate>

评论:我也尝试过使用 Canvas 而不是 Grid,结果相同。

然后,数据库将数据加载到 CSList(使用 ViciCoolStorage)并绑定到 ListBox:

StationList.ItemsSource = App.RouteViewModel.RouteStops;

评论:我尝试将 CSList 的元素添加到 ObservableCollection 并将其绑定到接口,但似乎没有任何改变。

问题: 我是否做错了什么会导致加载时间过长——即使只加载 10 个元素——或者这是正常的?您有什么建议可以让 DataBinding 获得更好的性能吗?

提前感谢您的回答!

对应的代码部分:

RouteViewModel.cs

private Route rRoute;
public Route Route
{
    get
    {
        if (rRoute != null)
        {
            return rRoute;
        }
        else
        {
            return new Route();
        }
    }
}

public void LoadRoute(string index)
{
    try
    {
        if (rRoute.RouteId != index)
        {
            RouteLoaded = false;
            StationsLoaded = false;
            TimetableLoaded = false;
        }
    }
    catch (Exception) { }

    this.index = index;

    if (!RouteLoaded)
    {
        NotifyPropertyChanging("Route");
        rRoute = Route.ReadSafe(index);
        RouteLoaded = true;
        NotifyPropertyChanged("Route");
    }
}

private CSList<RouteTime> rtLine;
public CSList<RouteTime> RouteStops
{
    get
    {
        if (rtLine != null)
        {
            return rtLine;
        }
        else
        {
            return new CSList<RouteTime>();
        }
    }
}

public void LoadRouteStops()
{
    LoadRoute(index);

    if (!this.StationsLoaded)
    {
        NotifyPropertyChanging("RouteStops");
        rtLine = rRoute.RouteTimes.FilteredBy("DirectionId = @DirectionId", "@DirectionId", this.direction).OrderedBy("TimeSpan");
        NotifyPropertyChanged("RouteStops");

        StationsLoaded = true;
    }
}

RouteView.xaml.cs

private string index;
private bool visszaut = false;

public RouteView()
{
    InitializeComponent();
    Loaded += new System.Windows.RoutedEventHandler(RouteView_Loaded);
}

void RouteView_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    DataContext = App.RouteViewModel;
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    NavigationContext.QueryString.TryGetValue("index", out index);

    App.RouteViewModel.LoadRoute(index);
    App.RouteViewModel.Direction = Convert.ToInt32(visszaut);
    App.RouteViewModel.LoadRouteStops();
    StationList.ItemsSource = App.RouteViewModel.RouteStops;
}

RouteTime.cs - 类实现

[MapTo("RouteTimes")]
public class RouteTime : CSObject<RouteTime, int>
{
    public int RouteTimeId
    {
        get
        {
            return (int)GetField("RouteTimeId");
        }
        set
        {
            SetField("RouteTimeId", value);
        }
    }

    public int RouteId
    {
        get
        {
            return (int)GetField("RouteId");
        }
        set
        {
            SetField("RouteId", value);
        }
    }

    public int StopId
    {
        get
        {
            return (int)GetField("StopId");
        }
        set
        {
            SetField("StopId", value);
        }
    }

    public int TimeSpan
    {
        get
        {
            return (int)GetField("TimeSpan");
        }
        set
        {
            SetField("TimeSpan", value);
        }
    }

    public Direction DirectionId
    {
        get
        {
            return (Direction)GetField("DirectionId");
        }
        set
        {
            SetField("DirectionId", value);
        }
    }

    [OneToOne(LocalKey = "StopId", ForeignKey = "StopId")]
    public Stop Stop
    {
        get
        {
            return (Stop)GetField("Stop");
        }
        set
        {
            SetField("Stop", value);
        }
    }

    [ManyToOne(LocalKey = "RouteId", ForeignKey = "RouteId")]
    public Route Route
    {
        get
        {
            return (Route)GetField("Route");
        }
        set
        {
            SetField("Route", value);
        }
    }
}

【问题讨论】:

    标签: listbox windows-phone


    【解决方案1】:

    好的,在这种情况下,渲染缓慢的原因似乎是 RouteTime 和 Stop 类之间的 [OneToOne] 连接。如果我绑定到存储在链接类中的任何变量,渲染需要很长时间。

    修复者

    我在需要显示结果的代码中添加了一个新的部分类。

    public partial class StopTimes
    {
        public int TimeSpan
        {
            get;
            set;
        }
    
        public string StopName
        {
            get;
            set;
        }
    }
    

    使用 Vici CoolStorage 中的临时查询,我进行了自己的查询以请求所需的数据,viola,一切都在那里,渲染时间不超过 1 秒。也许,在渲染过程中,它会一一请求带有 SQLQuery 的 StopName 字段?

    不知道,不过还是谢谢你的帮助:)

    【讨论】:

      【解决方案2】:

      DataBinding 在这种情况下不应该是问题——我从来没有遇到过任何问题。它肯定与您的 SQL 数据库有关。我有大约 200 个项目的列表,它在 100 毫秒的合理时间段内呈现良好。

      这要么是您的 SQL 实现,要么是您使用了错误的 ViciCoolStorage。发布您的代码。

      【讨论】:

      • 我已经在帖子中添加了相应的代码部分。它包含页面上呈现的对象的类实现、从数据库加载数据的 ViewModel 和视图本身。同时,我将尝试搜索另一个 SQLite 库并用它测试代码。
      【解决方案3】:

      您是否尝试过在 LoadRouteStops() 方法之外对列表进行过滤?也许在后面的代码而不是 viewModel 中?在 propertyChanging 和 propertyChanged 通知之间似乎有很多工作要做。

      【讨论】:

      • 看来我找到了问题的根源,我已经添加了问题的答案。感谢您的帮助!
      【解决方案4】:

      我很困惑:你如何在 Windows Phone 7 上执行本地 SQLite?您的意思是支持此功能的 WP8 吗? 在任何情况下,请考虑使用 LongListSelector(内置于 WP8 - WP7 中的工具包),因为当您有很多要渲染的项目时,它在虚拟化方面做得更好。

      【讨论】:

      • 我是一名 Windows Phone 7 开发人员,我正在使用 Vici CoolStorage 连接到数据库。 link
      【解决方案5】:

      这个问题主要是因为设置了很多绑定。尽量减少绑定并尝试在后面的代码上做艰苦的工作。如;

      “将字符串列表逐个绑定到 xaml”

      “通过 string.join 方法,只绑定一个文本块”

      我有

      <TextBlock Text="{Binding Times[0]}"/>
      <TextBlock Text="{Binding Times[1]}"/>
      ...
      <TextBlock Text="{Binding Times[9]}"/>
      

      又改成

      <TextBlock Text="{Binding TimesToLongString}"/>
      

      这解决了延迟问题。
      用于在 9 秒内加载 3 个项目。
      现在它在 110 毫秒内加载 10 个项目。

      要查看加载列表所需的时间,您可以查看this post

      【讨论】:

        猜你喜欢
        • 2011-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-09
        • 1970-01-01
        • 2012-12-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多