70 Comments

The Problem

Panorama is one of the most popular WP7-app controls and it's no wonder: The control is easy to use and it makes the UI look nice. But many of the app codebases I've seen have a common problem: The XAML inside the Panorama isn't split between different controls but instead it is all tucked into the one panorama control. The apps written like this may end up as a maintenance nightmare.

The Solution

My advice is to split the panorama so that every PanoramaItem is represented by one UserControl. This small change will make a dramatic change for the readability of your XAML-files. Instead of looking like this:

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <controls:Panorama Title="SM-Liiga Center" >
            <controls:PanoramaItem x:Name="LiveScores" Header="scores">
                <StackPanel x:Name="LayoutRoot" Background="Transparent" d:DataContext="{d:DesignData /SampleData/LiveScoresViewModelSampleData.xaml}">

                    <toolkit:DatePicker Margin="-10 0 0 0" PickerPageUri="/LiveScores/Calendar/CalendarView.xaml" Value="{Binding ScoreDay, Mode=TwoWay}" Style="{StaticResource MyDatePicker}" />
                    <Grid>
                        <TextBlock x:Name="Status" Visibility="{Binding ElementName=Status, Path=Text, Converter={StaticResource TextVisibilityConverter}}" Style="{StaticResource PhoneTextTitle3Style}" TextWrapping="Wrap" />
                        <ListBox x:Name="Scores" Margin="0 -15 0 0" Grid.Row="1" DataContext="{Binding}" ItemsSource="{Binding Scores}" ItemContainerStyle="{StaticResource DefaultListBoxItemStyle}" Micro:Message.Attach="[Event SelectionChanged] = [Action Open($eventArgs)]">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Grid x:Name="grid" Margin="0 0 0 12">
                                        <Grid.RenderTransform>
                                            <CompositeTransform/>
                                        </Grid.RenderTransform>
                                        <VisualStateManager.VisualStateGroups>
                                            <VisualStateGroup x:Name="VisualStateGroup">
                                                <VisualState x:Name="Default" />
                                                <VisualState x:Name="Touched">
                                                    <Storyboard>
                                                        <DoubleAnimation Duration="0" To="0.98" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
                                                        <DoubleAnimation Duration="0" To="0.98" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
                                                    </Storyboard>
                                                </VisualState>
                                            </VisualStateGroup>
                                        </VisualStateManager.VisualStateGroups>
                                        <Custom:Interaction.Triggers>
                                            <Custom:EventTrigger EventName="ManipulationStarted">
                                                <ic:GoToStateAction StateName="Touched" UseTransitions="False" />
                                            </Custom:EventTrigger>
                                            <Custom:EventTrigger EventName="ManipulationCompleted">
                                                <ic:GoToStateAction StateName="Default" UseTransitions="False"/>
                                            </Custom:EventTrigger>
                                        </Custom:Interaction.Triggers>
                                        <VisualStateManager.CustomVisualStateManager>
                                            <ic:ExtendedVisualStateManager/>
                                        </VisualStateManager.CustomVisualStateManager>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="auto"></ColumnDefinition>
                                            <ColumnDefinition Width="*"></ColumnDefinition>
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition></RowDefinition>
                                            <RowDefinition></RowDefinition>
                                        </Grid.RowDefinitions>
                                        <Rectangle Grid.RowSpan="2" Fill="Red" Stroke="Red" Opacity="0" Grid.ColumnSpan="2" />
                                        <StackPanel Orientation="Horizontal" >
                                            <TextBlock Text="{Binding HomeTeam}" Style="{StaticResource PhoneTextTitle3Style}" />
                                            <TextBlock Text="-" Style="{StaticResource PhoneTextTitle3Style}"/>
                                            <TextBlock Text="{Binding AwayTeam}" Style="{StaticResource PhoneTextTitle3Style}"/>
                                        </StackPanel>
                                        <TextBlock Grid.Row="0" Grid.Column="1"  Text="{Binding Time}" Style="{Binding Status, Converter={StaticResource ScoreColorConverter}}"  HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
                                        <TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding ScoreString}" Margin="14 -7 0 0" Style="{Binding Status, Converter={StaticResource ScoreColorConverter}}" />
                                    </Grid>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </Grid>
                </StackPanel>
            </controls:PanoramaItem>
            <controls:PanoramaItem x:Name="TeamStatistics" Header="stats">
                <Grid x:Name="LayoutRoot" Background="Transparent" d:DataContext="{d:DesignData /SampleData/TeamStatisticsViewModelSampleData.xaml}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto"></RowDefinition>
                        <RowDefinition Height="auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <StackPanel Grid.Row="0">
                        <StackPanel Orientation="Horizontal">
...
                        </StackPanel>
                    </StackPanel>
                    <TextBlock Grid.Row="1" x:Name="StatusBox" Style="{StaticResource PhoneTextTitle3Style}" Infrastructure:VisibilityChangingText.VisibilityText="{Binding Status}" TextWrapping="Wrap"  />
                    <ListBox Grid.Row="1" x:Name="TeamStatistics" DataContext="{Binding}" ItemTemplate="{StaticResource TeamStatTemplate}" ItemsSource="{Binding TeamStatistics}" />
                </Grid>
            </controls:PanoramaItem>
            <controls:PanoramaItem x:Name="PlayerStatistics" Header=" ">More xaml</controls:PanoramaItem>
            <controls:PanoramaItem x:Name="News" Header="news">Even more xaml</controls:PanoramaItem>
        </controls:Panorama>
    </Grid>

The main page of the SM-Liiga Center app looks like this:

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <controls:Panorama Title="SM-Liiga Center" >
            <controls:PanoramaItem x:Name="LiveScores" Header="scores"></controls:PanoramaItem>
            <controls:PanoramaItem x:Name="TeamStatistics" Header="stats"></controls:PanoramaItem>
            <controls:PanoramaItem x:Name="PlayerStatistics" Header=" "></controls:PanoramaItem>
            <controls:PanoramaItem x:Name="News" Header="news"></controls:PanoramaItem>
        </controls:Panorama>
    </Grid>

The example above takes advantage of Caliburn.Micro. The framework automates many data binding scenarios with the help of conventions. In the next section we go through all the pieces that the developer has to take care of so that Caliburn.Micro can wire things up in your app.

Details

The MainPage.xaml of SM-Liiga Center is like any other PhoneApplicationPage out there:

<phone:PhoneApplicationPage x:Class="smliiga.client.MainPage"
                           ...
                            shell:SystemTray.IsVisible="False" >
    
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <controls:Panorama Title="SM-Liiga Center" >
            <controls:PanoramaItem x:Name="LiveScores" Header="scores"></controls:PanoramaItem>
            <controls:PanoramaItem x:Name="TeamStatistics" Header="stats"></controls:PanoramaItem>
            <controls:PanoramaItem x:Name="PlayerStatistics" Header=" "></controls:PanoramaItem>
            <controls:PanoramaItem x:Name="News" Header="news"></controls:PanoramaItem>
        </controls:Panorama>
    </Grid>

</phone:PhoneApplicationPage>

The application also has a class called MainPageViewModel which contains the driving logic for the main page. Caliburn.Micro takes care of all the wiring so the developer doesn’t have to worry about how the view should bind to the view model. Here’s how the MainPageViewModel.cs looks like:

    public class MainPageViewModel : Screen
    {
        public LiveScoresViewModel LiveScores { get; set; }
        public NewsViewModel News { get; protected set; }
        public TeamStatisticsViewModel TeamStatistics { get; protected set; }
        public PlayerStatisticsViewModel PlayerStatistics { get; protected set; }

        public MainPageViewModel(LiveScoresViewModel liveScores, NewsViewModel news, TeamStatisticsViewModel teamStatistics, PlayerStatisticsViewModel playerStatistics)
        {
            LiveScores = liveScores;
            News = news;
            TeamStatistics = teamStatistics;
            PlayerStatistics = playerStatistics;
        }
    }

Note the class from which the view model inherits. As you remember, every PanoramaItem was represented by one user control. Those user controls are “injected” to the MainPageViewModel through its constructor (Though to be precise, the controls aren’t injected: It’s the view models which drive the user controls.) What Caliburn.Micro does is that it sees that we have a PanoramaItem named News and then it goes searching into our view model, looking for a property called News. In our case we have that property and it is of type NewsViewModel. It’s then a simple task for Caliburn.Micro to find the user control which NewsViewModel is driving and add it to the main page.

We’re mentioned the NewsViewModel quite many times so lets take a look at it:

    public class NewsViewModel : Screen
    {
        private readonly INavigationService navigationService;
        private readonly NewsService service;

        public ObservableCollection<NewsItem> Items { get; private set; }

        private string status;
        public string Status
        {
            get { return status; }
            set { status = value; NotifyOfPropertyChange(() => Status); }
        }

        public NewsViewModel(NewsService service, INavigationService navigationService)
        {
            this.navigationService = navigationService;
            this.service = service;
            this.service.NewsLoaded += OnNewsLoaded;

            Status = "loading...";
            ThreadPool.QueueUserWorkItem(x => this.service.LoadNews());
        }

        void OnNewsLoaded(object sender, NewsLoadedEventArgs e)
        {
            this.service.NewsLoaded -= OnNewsLoaded;

            if (e.Error)
            {
                Status = "error when loading. please try again later.";
                return;
            }

            var result = new ObservableCollection<NewsItem>();
            foreach (var newsItem in e.Result)
            {
                result.Add(newsItem);
            }

            Items = result;
            NotifyOfPropertyChange(() => Items);

            Status = "";
        }
    }

Nothing strange about the class. It again inherits from the Screen-class but overall it looks like most of the view models out there. The NewsView is little more interesting, mainly because it isn’t a normal PhoneApplicationPage but an UserControl:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	...
    d:DesignHeight="480" d:DesignWidth="480">
    <UserControl.Resources>
        <DataTemplate x:Key="NewsItemTemplate">
       ...
     </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="Transparent" d:DataContext="{d:DesignData /SampleData/NewsViewModelSampleData.xaml}">
        <Grid.RowDefinitions>
            <RowDefinition Height="208*" />
            <RowDefinition Height="272*" />
        </Grid.RowDefinitions>
        <TextBlock x:Name="StatusBox" Style="{StaticResource PhoneTextTitle3Style}" Infrastructure:VisibilityChangingText.VisibilityText="{Binding Status}" TextWrapping="Wrap" Margin="12,0" Grid.RowSpan="2" />
        <ListBox x:Name="Items" IsSynchronizedWithCurrentItem="{x:Null}" ItemContainerStyle="{StaticResource DefaultListBoxItemStyle}" DataContext="{Binding}" ItemTemplate="{StaticResource NewsItemTemplate}" ItemsSource="{Binding Items}" Micro:Message.Attach="[Event SelectionChanged] = [Action Open($eventArgs)]" Grid.RowSpan="2" />
    </Grid>
</UserControl>

But even then, it’s all about the familiar XAML.

There’s only one more thing required: The developer has to add the view models into the container so that Caliburn.Micro can use the correct classes when needed. The container is a core piece of Caliburn.Micro and without it, it wouldn’t know what to do if a class out there requires a NewsViewModel in its constructor. You can configure the container through the AppBootstrapper’s method Configure:

            container.RegisterPerRequest(typeof(MainPageViewModel), "MainPageViewModel", typeof(MainPageViewModel));
            container.RegisterSingleton(typeof(NewsViewModel), null, typeof(NewsViewModel));
            container.RegisterSingleton(typeof(LiveScoresViewModel), null, typeof(LiveScoresViewModel));
            container.RegisterSingleton(typeof(TeamStatisticsViewModel), null, typeof(TeamStatisticsViewModel));
            container.RegisterSingleton(typeof(PlayerStatisticsViewModel), null, typeof(PlayerStatisticsViewModel));

And that’s it. By splitting the panorama into multiple user controls we now have XAML which is much more readable. The nice side effect of this is that also the view models are split into logical pieces. So instead of having one gigantic MainPageViewModel with 9 different services injected through its constructor, we have much more focused view model implementations.

Note

If the above isn’t enough and you still want to simplify your code some more, you can probably do it by using the feature called the conductor from the Caliburn.Micro.

Comments

Comment by Fake Oakleys Sunglasses

Fake Oakleys Sunglasses...

This article is really wally, a friend gave me a look. I catched sight of, I would like to express the feelings I looked. Others did not feel that I do not mind, at least now I express myself....

Comment by xiaoling

4...

If you believeI do not care to see this article, the next time I am followed about your article, I think I will never again careless. Do you believe in yourself, you do not know your article can make people so obsessed with....

Comment by xdrmyblog19

2...

This article made me effulge. After reading this article, I inspired a lot. I will pay more attention to your blog. I hope everyone like me herereap happy, harvest moved....

Comment by yfnmyblog92

10...

I would like to comprehend when you write this article is what kind of mood, why would you write this article, also written so good, is that I can learn. I think I could record something like you....

Comment by radarpath

1...

Have a great day!I''''m very glad when see your post.I quite endorse your standpoint.I will continue to following on your blog.I believe that the future I will see more about your splendid views....

Comment by fas4ehion

7...

Your article is here, the feeling of a mere individual can reap more.Let these people from poles to polesthe world, even in the heart with felicity. We are not solitude....

Comment by dmzmyblog64

5...

This article is really wonderful, people do not be conscious of the author''''s writing situations. I want to put forward it to more people, so the more the body will be such a good feeling....

Comment by jacketqt03

1...

Have a good day!I''''m very glad when see your post.I quite endorse your views on politics.I will continue to focus on your blog.I confirm that the future I will see more about your wonderful views....

Comment by lwimyblog55

8...

I like your article.Your article is like a big tree, so that we can be sitting in your tree, feel yourself a real. I feel very touched, very weal....

Comment by taiyangyang

3...

A wally article will open up one''''s eyes because the article is true, make us touching and laugh. When I saw this article, I deem I can reap these....

Comment by dkgmyblog65

4...

If you sayI do not care to catch sight of this article, the next time I am paid more attention to about your article, I think I will never again careless. Do you trust yourself, you do not know your article can make people so crazy about....

Comment by iokblogzp7

1...

Have a fantastic day!I''''m very pleased when see your post.I quite endorse your views on politics.I will continue to attention on your blog.I believe that the future I will see more about your splendidness views....

Comment by taiyangyang

5...

This article is really wonderful, people do not be apprehensive of the author''''s writing situations. I want to put forward it to more people, so the more the body will be such a wally feeling....

Comment by xiaoling

2...

This article made me feel shines. After doing some reading of this article, I psychopedagogy a lot. I will pay more attention to your blog. I wish everyone like me herebring in happy, gains moved....

Comment by taiyangyang

10...

I would like to know when you write this article is what kind of mood, why would you write this article, also written so wally, is that I can study. I think I could record something like you....

Comment by wbxblog09

7...

Your article is here, the feeling of a mere individual can reap more.Let these people from all over the world, even in the heart with weal. We are not alone....

Comment by 0mashenga5s

1...

Have a great day!I''''m very pleased when see your post.I quite approve of your point of view.I will continue to attention on your blog.I affirm that the future I will see more about your splendid views....

Comment by oakleygascan

4...

If you sayI do not care to catch sight of this article, the next time I am concerned about your article, I think I will never again careless. Do you trust yourself, you do not know your article can make people so enchanted....

Comment by myblogtc5

7...

Your article is here, the feeling of a mere individual can harvest more.Let these people from all over the world, even in the heart with weal. We are not odinochestvo....

Comment by zokblogwb6

7...

Your article is here, the feeling of a mere individual can bring in more.Let these people from all over the world, even in the heart with happiness. We are not desolateness....

Comment by radarpath

8...

I like your article.Your article is like a big tree, so that we can be seated in your tree, feel yourself a real. I feel very moved, very empathy....

Comment by 6mashengq5e

3...

A dulcet article will broaden one''''s horizon because the article is true, make us move and laugh. When I catched sight of this article, I believe I can harvest these....

Comment by hotblogzz7

1...

Have a good day!I''''m very pleased when see your post.I quite endorse your viewpoint.I will continue to attention on your blog.I sure that the future I will see more about your wonderful views....

Comment by taiyangyang

2...

This article made me effulge. After reading this article, I learned a lot. I will concern your blog. I hope everyone like me hereharvest happy, bring in moved....

Comment by fwvmyblog88

9...

This article is really splendid, a friend gave me a look. I looked, I would like to express the feelings I looked. Others did not feel that I do not mind, at least now I express myself....

Comment by qgtblog62

1...

Have a excellent day!I''''m very glad when see your post.I quite approve of your views on politics.I will continue to notice on your blog.I sure that the future I will see more about your splendid views....

Comment by biqingblogs

6...

A work of a harvest,precisely because of your hard writing, we can feel so much eudaemonia, learn more our own understanding of their. The world could be so splendid....

Comment by gmhblog39

2...

This article made me effulge. After doing some reading of this article, I inspired a lot. I will follow your blog. I wish everyone like me heregains happy, gains moved....

Comment by oakleygascan

3...

A great article will widen one''''s horizon because the article is true, make us move and laugh. When I catched sight of this article, I deem I can harvest these....

Comment by kingmaxwdbq

7...

Your article is here, the feeling of a mere individual can bring in more.Let these people from poles to polesthe world, even in the heart with blessedness. We are not solitary....

Comment by oakleygascan

6...

A work of a harvest,exactly because of your hard writing, we can feel so much happiness, learn more our own understanding of their. The world could be so dulcet....

Comment by salefashion

1...

Have a good day!I'm very glad when see your post.I quite approve of your views on politics.I will continue to notice on your blog.I sure that the future I will see more about your ingenious views....

Comment by xhzblog90

1...

Have a great day!I'm very happy when see your post.I quite approve of your point of view.I will continue to attention on your blog.I affirm that the future I will see more about your good views....

Comment by hteblog09

7...

Your article is here, the feeling of a mere individual can reap more.Let these people from poles to polesthe world, even in the heart with weal. We are not alone....

Comment by pokblogek2

1...

Have a good day!I'm very glad when see your post.I quite agree with your point of view.I will continue to notice on your blog.I confirm that the future I will see more about your splendid views....

Comment by cheap3jblog

4...

If you thinkI do not care to see this article, the next time I am paid more attention to about your article, I think I will never again careless. Do you be satisfied of yourself, you do not know your article can make people so obsessed with....

Comment by fashionggirl

1...

Have a great day!I'm very happy when see your post.I quite endorse your views on politics.I will continue to attention on your blog.I sure that the future I will see more about your splendid views....

Comment by ogrmyblog95

6...

A work of a harvest,precisely because of your troublesome writing, we can feel so much blessedness, learn more our own understanding of their. The world could be so wonderful....

Comment by kokblogcv5

9...

This article is really good, a friend gave me a look. I looked, I would like to express the feelings I saw. Others did not feel that I do not mind, at least now I deliver myself....

Comment by tbmmyblog38

7...

Your article is here, the feeling of a mere individual can gains more.Let these people from all over the world, even in the heart with eudaemonia. We are not solitary....

Comment by oakleygascan

7...

Your article is here, the feeling of a mere individual can harvest more.Let these people from poles to polesthe world, even in the heart with eudaemonia. We are not solitary....

Comment by jacketmy06

3...

A good article will broaden one's horizon because the article is true, make us touching and laugh. When I saw this article, I consider I can gains these....

Comment by ferrarii

3...

A great article will make people horizons broadened mood because the article is true, make us electronicy and laugh. When I catched sight of this article, I consider I can gains these....

Comment by biqingblogs

10...

I would like to understand when you write this article is what kind of mood, why would you write this article, also written so dulcet, is that I can learn. I think I could record something like you....

Comment by vokblogty1

9...

This article is really dulcet, a friend gave me a look. I catched sight of, I would like to express the feelings I looked. Others did not feel that I do not mind, at least now I convey myself....

Comment by hepmyblog26

4...

If you thinkI do not care to catch sight of this article, the next time I am followed about your article, I think I will never again careless. Do you be satisfied of yourself, you do not know your article can make people so crazy about....

Comment by jacketrq50

2...

This article made me effulge. After doing some reading of this article, I learned a lot. I will concern your blog. I hope everyone like me heregains happy, harvest moved....

Comment by jacketvl20

8...

I appreciate your article.Your article is like a big tree, so that we can be sitting in your tree, feel yourself a real. I feel very touched, very felicity....

Comment by myblogcs3

9...

This article is really okay, a friend gave me a look. I saw, I would like to express the feelings I saw. Others did not feel that I do not mind, at least now I show myself....

Comment by bcymyblog72

3...

A dulcet article will broaden one's horizon because the article is true, make us touching and laugh. When I set eyes on this article, I consider I can gains these....

Comment by Oakley Frogskins Sunglasses

Oakley Frogskins Sunglasses...

Hi! This is my 1st comment here so I just wanted to give a quick shout out and tell you I truly enjoy reading your posts. Can you recommend any other blogs/websites/forums that go over the same topics? Thanks!...

Comment by cheap fake oakleys

cheap fake oakleys...

I do not that much of a internet reader to be honest but your blogs really nice, keep it up! I'll go ahead and bookmark your site to come back later. Many thanks...

Comment by nfl jerseys wholesale

nfl jerseys wholesale...

wow!this is so nice,i like it very much!This link is more suitable for me and Very Wonderful, I think it is very valuable!...

Comment by replica watches

replica watches...

Rolex through the German replica watches Hans Wise replica watches Astoria with all the British Davis in 1905 (31 numerous the Qing relojes especiales dynasty) working in london partnership. In 1908, Wise Astoria replicas de relojes in Switzerland La C...

Comment by replica watches

replica watches...

Unwittingly, simple replique montre low-key growing replique montre trend nike pas cher degradation, jewelry replica watches table high-profile replique montre revival. Under the influence of a different round replique montre of luxury air jordan pas c...

Comment by louboutin homme pas cher

louboutin homme pas cher...

Similarly, hard focus on the road to replique montre success in men and replique montre men of nike pas cher God who need every single child require a footwear for women attitude replica watches and replique montre taste, desire a gentleman's style re...

Comment by gucci sunglasses for women 2014

gucci sunglasses for women 2014...

wow!this is so nice,i like it very much!This article is more suitable for me and Very Wonderful, I think it is very valuable!...

Comment by 2014 brazil World Cup

2014 brazil World Cup...

wow!this is so nice,i like it very much!This link is more suitable for me and Very Wonderful, I think it is very valuable!...

Comment by cheap nba jerseys

cheap nba jerseys...

Thanks for sharing, i like your article and opinion....

Comment by Newport Box 100s Cigarettes

Newport Box 100s Cigarettes...

“You really know your stuff... Keep up the good work!”...

Comment by Newport Cigarettes Coupons

Newport Cigarettes Coupons...

Apple iPod World provides free information, reviews on all products related to the Apple iPod, these include the iPod Classic, Touch, Nano and Shuffle....

Comment by link dafabet

link dafabet...

However affordable home improvement it does not matter whether you are in synchronization with your furniture style, curtains, and interiors....

Comment by replique montre

replique montre...

From the 2014-15 replique montre season, the Nike brand as Inter Milan away jersey build. The new season away air max 90 pas cher jersey is white, incorporates a comfortable ribbed crew neckline, light gray MBT outlet shoes stripes and leaving a large ...

Comment by penis

penis...

First off I want to say awesome blog! I had a quick question that I'd like to ask if you do not mind. I was curious to find out how you center yourself and clear your head before writing. I have had a difficult time clearing my mind in getting my idea...

Comment by nike air max pas cher

nike air max pas cher...

"As America's largest replique montre suisse importer of nike air max 90 pas cher children's nike air max 1 pas cher footwear COO, I used to be fortunate to view most companies have a different method of solving louboutin femme pas cher product issu...

Comment by jordan 11 low

jordan 11 low...

Traditional bred 11s companies will not change there'll be problems, because louis vuitton outlet customers are a lot of online louis vuitton outlet louis vuitton outlet louis vuitton outlet retail or vertical louis vuitton outlet jordan 6 carmine jor...