如何提高的Windows Phone 8 Map控件性能 [英] How to improve Windows Phone 8 Map control performance

查看:128
本文介绍了如何提高的Windows Phone 8 Map控件性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Windows Phone 8的应用程序,我有其中有平面(图钉)收集地图的控制。

In my Windows Phone 8 app, I have map control which has collection of planes (pushpins).

地图在XAML中这样定义的:

Map is defined in xaml like this:

<maps:Map x:Name="Map">
    <maptk:MapExtensions.Children>

        <maptk:MapItemsControl Name="Planes" ItemTemplate="{StaticResource PlaneTemplate}"/>

    </maptk:MapExtensions.Children>
</maps:Map>

MapItemsControl被绑定到对象的集合(的ObservableCollection)的视图模型这样的飞机:

Planes MapItemsControl is bind to collection (ObservableCollection) of objects in view model like this:

private ObservableCollection<IPlane> _planes;
public ObservableCollection<IPlane> Planes
{
    get { return _planes; }
    set
    {
        _planes = value;
        NotifyOfPropertyChange(() => Planes);
    }
}

public async void GetPlanes()
{
    IReadOnlyCollection<IPlane> planes = await realtimePlanes.GetAllPlanesAsync();

    foreach (IPlane newPlane in planes)
    {
        this.Vehicles.Add(newPlane);
    }
}

在我所说的GetPlaes(),从网页API获取飞机和更新集合,整个应用程序freeses为几秒钟。通常有一些像150 - 300项飞机collectoin

When I call the GetPlaes(), to get the planes from web api and update the collection, the whole app freeses for couple of seconds. Typically there is something like 150 - 300 items in Planes collectoin.

我应该如何改善这让用户体验更好,以消除滞后,当我更新飞机收藏?

How should I improve this to make the user experience better, to remove the lag when I update the Planes collection?

我可以以某种方式迫使这个集合更新在后台线程进行(?)或有问题的地图操控性能?它不能得出所有的项目足够快一气呵成?

Can I somehow force this collection update to be made in background thread(?) or is the problem map control performance? It can not draw all items fast enough in one go?

下面是一些code,我的实际应用程序是如何工作的。

Here is some more code, how my actual app works.

刚刚建立快速和肮脏的测试类/服务生成测试架:

Just build quick and dirty test class/service to generate test planes:

public class TestRealtimePlaneService : IRealtimePlaneService
{
    private Random random;

    public async Task<IEnumerable<IRealtimePlane>> GetAllPlanesAsync()
    {
        this.random = new Random();

        int count = 350;
        double x0 = 24.9375;
        double y0 = 60.170833;
        int radius = 8000;

        List<TestRealtimePlane> planes = new List<TestRealtimePlane>();

        for (int i = 0; i < count; i++)
        {
            planes.Add(new TestRealtimePlane() { Location = getLocation(x0, y0, radius), Bearing = 1 });
        }

        await Task.Delay(5000); // Just to simulate webservice call

        return planes;
    }

    // Taken from http://gis.stackexchange.com/questions/25877/how-to-generate-random-locations-nearby-my-location
    public GeoCoordinate getLocation(double x0, double y0, int radius)
    {
        double radiusInDegrees = radius / 111000f;

        double u = this.random.NextDouble();
        double v = this.random.NextDouble();
        double w = radiusInDegrees * Math.Sqrt(u);
        double t = 2 * Math.PI * v;
        double x = w * Math.Cos(t);
        double y = w * Math.Sin(t);

        double new_x = x / Math.Cos(y0);

        double foundLongitude = new_x + x0;
        double foundLatitude = y + y0;

        return new GeoCoordinate(foundLatitude, foundLongitude);
    }
}

这是实际的地图组件

<maps:Map x:Name="Map">
    <maptk:MapExtensions.Children>

        <maptk:MapItemsControl Name="Planes">
            <maptk:MapItemsControl.ItemTemplate>
                <DataTemplate>
                    <maptk:Pushpin GeoCoordinate="{Binding Location}" PositionOrigin="0.5,0.5">
                        <maptk:Pushpin.Template>
                            <ControlTemplate TargetType="maptk:Pushpin">
                                <Grid Width="45" Height="45" Background="Transparent">
                                    <Polygon Fill="Yellow" Points="22,0 34,13, 12,13" Width="45" Height="45" RenderTransformOrigin="0.5,0.5">
                                        <Polygon.RenderTransform>
                                            <RotateTransform CenterX="0.5" CenterY="0.5" Angle="{Binding Bearing}"/>
                                        </Polygon.RenderTransform>
                                    </Polygon>
                                    <Ellipse Fill="Yellow" Stroke="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Width="15" Height="15" StrokeThickness="2" />
                                </Grid>
                            </ControlTemplate>
                        </maptk:Pushpin.Template>
                    </maptk:Pushpin>
                </DataTemplate>
            </maptk:MapItemsControl.ItemTemplate>
        </maptk:MapItemsControl>

    </maptk:MapExtensions.Children>
</maps:Map>

看来,图钉模板也影响相当大量用于性能。如果我从图钉取出我自己的控件模板,这个工程只是增加得快一点。

It seems that the pushpin template also affects quite lot for the performance. If I remove my own control template from pushpin, this works gain just little bit faster.

推荐答案

当您使用WPToolkit的MapExtension来显示你正在寻找的麻烦图钉。你会想到,绑定的ItemsSource到的ObservableCollection&LT; T&GT; 为您提供了非常方便的方法好的和放大器一起更新您的地图;流畅的用户体验。

When you use WPToolkit's MapExtension to display pushpins you are looking for trouble. You'd expect that Binding ItemsSource to ObservableCollection<T> gives you easy way to update your map along with nice & smooth user experience.

该死的!我引用(自己):

Hell no! And I quote (myself):

WPToolkit的MapExtensions吸驴的屁股。它的种类的
  组件,让你问,为什么你在开始编程
  第一位。

WPToolkit's MapExtensions sucks donkey's arse. It's the kind of a component that makes you question why you started programming in the first place.

可以绑定的ItemsSource 来集合,但你不能这样做,在XAML。不,你必须自己去挖的ItemsSource和codebehind明确设置它。

You can bind ItemsSource to collection but you can't do that in XAML. No, you have to dig up the ItemsSource yourself and set it explicitly in codebehind.

var control = MapExtensions.GetChildren(MyMap).OfType<MapItemsControl>().FirstOrDefault();

并不坏,但等待,还有更多!如果收藏有项目,你不能只是更换新的,否则你会用一个异常结束。不,相反,你必须清除的项目,然后由一个增加新的项目之一。恩,那就对了。一个接一个!

Not that bad, but wait, there's more! If collection has items, you can't just replace it with new one or you'll end up with an exception. No, instead you have to clear the items and then add new items one by one. Yes, that's right. One-by-one!

var planes = (await PlaneRepository.GetAllPlanesAsync()).ToList();

if (Planes.Any())
    Planes.Clear();

foreach (var plane in planes)
    Planes.Add(plane);

在更新集合则UI被阻塞。没有调度的BackgroundWorker 也不任务&LT; T&GT; 这让你解决这个问题。

When you update the collection then the UI is blocked. There is no Dispatcher, BackgroundWorker nor Task<T> that gets you around this.

如果有人有任何怀疑,然后通过各种手段,请大家指出我哪里错了。我设置了一个公共GitHub库主分支的),以从叉子。

If someone has any doubts, then by all means, please point out where I went wrong. I set up a public GitHub repo (master branch) to fork from.

&NBSP;

为了使地图无阻塞你必须做一些妥协,干脆沟MapExtensions。当你创建新的 MapOverlay ,有一个图钉的内容,并手动添加这些到您的地图,用户界面​​保持响应。

In order to make map non-blocking you have to do some compromises and ditch the MapExtensions altogether. When you create new MapOverlay, having one Pushpin as content, and add those manually to your map, UI remains responsive.

但这里有一个问题,太。如果添加MapOverlays的很多的一次,那么你仍然有短暂冻结。如果你延迟除了每个项目的目的上(例如,75ms),那么你必须在那里图钉一个地图一个在显示和UI响应保持不错的效果。

But there's a catch, too. If you add lot's of MapOverlays at once then you still have that brief freeze. If you delay addition of each item on purpose (say, 75ms) then you have nice effect where pushpins appear on your map one by one and UI remains responsive.

Task.Factory.StartNew(() =>
    {
        if (message.Delay != null)
        {
            foreach (var plane in message.Planes)
            {
                AddPins(new[] {plane});
                Thread.Sleep(message.Delay.Value);
            }
        }
    });

&NBSP;

private void AddPins(IEnumerable<IPlane> planes)
{
    DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            foreach (var plane in planes)
            {
                var pushpin = new Pushpin
                    {
                        Style = Resources["PlaneStyle"] as Style
                    };

                var pushpinOverlay = new MapOverlay
                    {
                        GeoCoordinate = plane.Location,
                        Content = pushpin
                    };
                _pushpinLayer.Add(pushpinOverlay);
            }
        });
}

&NBSP;

响应地图示例,使用MapOverlays,位于同一GitHub库 但在无地图的扩展分支。

Responsive map example, using MapOverlays, is located in the same GitHub repo but in no-map-extensions branch.

这是你如何改进的Windows Phone 8 Map控件的性能。)

That's how you improve Windows Phone 8 Map control performance :).

这篇关于如何提高的Windows Phone 8 Map控件性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆