I have a Panorama control, which has an ExpanderView Item (from Silverlight toolkit).
My client wants this page to be customizable. Thats why I created 3 level of binding:
The PanoramaItems, the ExpanderView headers and the ExpanderView content.
The problem when I set the itemssource of the Panorama control. it takes about 5 seconds to show the items.
Any idea how I can solve this?
C# code:
private void panorama_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = App.Products;
}
XAML Code:
<controls:Panorama Loaded="panorama_Loaded" x:Name="panorama" ItemsSource="{Binding}">
<controls:Panorama.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Sub_Products}" >
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:ExpanderView Header="{Binding}" Expander="{Binding}" ItemsSource="{Binding Sub_Sub_Products}">
<toolkit:ExpanderView.ExpanderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image VerticalAlignment="Center" Source="Images/List.png" Width="25" />
<TextBlock Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</toolkit:ExpanderView.ExpanderTemplate>
<toolkit:ExpanderView.ItemTemplate>
<DataTemplate>
<Grid Margin="-30,0,0,0" Background="White" Width="450" Tap="Grid_Tap" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding ImageSource}" />
<StackPanel VerticalAlignment="Top" Grid.Column="1">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Description}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<TextBlock Margin="0,12,32,0" Grid.Row="1" Text="Learn more" />
</StackPanel>
</Grid>
</DataTemplate>
</toolkit:ExpanderView.ItemTemplate>
</toolkit:ExpanderView>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
You could try to collapse the panorama items that are off screen and only set visibility to visible on demand. That should at least reduce the size of the visible tree.
A good way to find the slow parts is to use the profiler in Visual Studio. You will find one frame which is really slow (it will have a render time of 5 seconds in your case). Then dig into the visual tree of that frame and see which elements took a long time to render and try to optimize these.
Remove the ExpanderView ItemsSource binding in xaml and bind to it when the Expander is manupulated in code. Just leave it as ItemsSource="{Binding}". That way you will dynamically build you visual tree as the user taps on the expander.
The event handler is something like below. I am assuming Product is the type in your App.Products list. Also ensure that you hook up the event in your xaml for the expander.
private void ExpanderView_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
var expander = sender as ExpanderView;
expander.ItemsSource = (expander.DataContext as Product).Sub_Sub_Products;
}
Hope this solves your slow loading issues and is not too late at this time.
Related
I have a list to show where we show repeat information from SQlite database to user. In this we show basically the product price, name and type. Usually a user will have 10-15 of such records.
Problem is it take 10+ sec to display the list. Now, the architecture of application. On page load of Shell application we fetch the information from web request and store that in SQlite and then Bind the Result from Sqlite StackLayout with Bindable Property. But it took more than 10-11 Sec to display us.
So we change it to Grid with Bindable property and results are same. Though I don't like CollectionView (as I found their select property weird. ) We use CollectionView with dataTemplate as Grid (as we have some tabular information to show) . The results still take same 10+ secs to load up.
i.e. I use Stacklayout, Grid, CollectionView, it take that much time. We are not using the ObservableCollection to bind, but our class elements are all INotifyPropertyChanged. So, I try to disable it but still even when I do not inherity INotifyPropertyChanged and remove "OnPropertyChanged" calls it still take same time.
However, when I reduce the information to just show the name of product (through binding) it reduce to 5 secs. Which is still a lot as a Collection View with just 10 records and showing one Bindable Grid showing result in 5 second is lot more than expected. I understand my other data (which call functions) maybe slowing it down but can we reduce those 5 second somehow?
I cannot share much of class, but some of properties are pretty straight forward Property with INotifyPropertyChange on string or int values.
Here is Code for loading CollectionView
public async Task LoadSearch()
{
CurrentState = LayoutState.Loading;
try
{
var o = await PatientMedicine.FetchPatientMedicine();
if (o)
{
var _sr = (await DBCoreAsync.GetDataAsync<PatientMedicine>())?.OrderBy(x => x.PatientMedID).ToList();
if (_sr != null)
{
SearchResults = _sr;
}
CurrentState = LayoutState.Success;
}
else
{
CurrentState = LayoutState.Error;
}
}
catch (Exception ex)
{
CurrentState = LayoutState.Error;
}
}
Here is Collection itself.
<CollectionView ItemsSource="{Binding SearchResults}" ItemSizingStrategy="MeasureFirstItem">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="0,7" ColumnSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<BoxView BackgroundColor="{Binding LowStock, Converter={StaticResource BoolToColorReverse}}" CornerRadius="5,0,5,0" />
<Grid Grid.Column="1" Margin="0"
Padding="10,5" BackgroundColor="{StaticResource PrimaryLight2}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.Row="0" Source="{Binding Medicine.RxIcon}" ></Image>
<Label Grid.Column ="1" Grid.Row="0" Style="{StaticResource GeneralLabelBlack}" Text="{Binding Medicine.MedicineName}"></Label>
<Button Grid.Column="2" Grid.Row="0" Command="{Binding Path=BindingContext.NavigateToMedicineReminder, Source={x:Reference Name=MedicineListPageName}}" CommandParameter="{Binding .}"
BackgroundColor="Transparent" VerticalOptions="Center" HorizontalOptions="End" ImageSource="{FontImage FontFamily=FontAwesomeSolid, Glyph=, Color={StaticResource Primary},Size=16}" ></Button>
<Image Grid.Column="0" Grid.Row="1"
Source="{StaticResource ImageSourceIconClockOpenHand}"></Image>
<Label Grid.Column ="1" Grid.Row="1" Text="{Binding RepeatStatusFormatted}"></Label>
<Image Grid.Column="0" Grid.Row="2"
Source="{StaticResource ImageSourceIconStock}"></Image>
<Label Grid.Column ="1" Grid.Row="2" Text="{Binding StockAndRequirement}"></Label>
<Image Grid.Column="0" Grid.Row="3"
Source="{StaticResource ImageSourceIconClock}"></Image>
<Label Grid.Column ="1" Grid.Row="3" Text="{Binding NextReminder}"></Label>
<Label Grid.Column ="0" Grid.Row="4" Grid.ColumnSpan="2" Text="{Binding Medicine.AilmentString}"></Label>
<Label Grid.Column ="0" Grid.ColumnSpan="2" Grid.Row="5" IsVisible="{Binding LowStock}" Text="Stock running low. Order a refill now" HorizontalOptions="End"></Label>
<Button Grid.Column="2" Grid.Row="5" Command="{Binding Path=BindingContext.AddtoCart, Source={x:Reference Name=MedicineListPageName}}" CommandParameter="{Binding .}"
BackgroundColor="Transparent" IsVisible="{Binding LowStock}" VerticalOptions="Center" HorizontalOptions="End" ImageSource="{FontImage FontFamily=FontAwesomeSolid, Glyph=, Color={StaticResource Primary},Size=16}" />
</Grid>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
To add more information: I am okay with Internet load time which is <=1.5 seconds the time I calculate and show here is exclusively for When I set the ViewModel to Values from temporary variable to main variable I did it just to see if DB access is slow or not. (to step it out). I have my control inside a StackLayout that use Xamarin Community Toolkit statelayout.
Also I go through MS's Suggestion on optimizing performance about Compile XAML etc, but since it is new App using Xamarin Forms 5.0 I don't think it is problem as it is already set by default.
I have tried to make all the items in the itemtemplate into a single view as like in the below image, how to achieve this by using Xamarin CarouselView, i am using like this
carousel = new CarouselView();
carousel.BindingContext = this;
carousel.ItemTemplate = itemTemplate;
carousel.SetBinding(CarouselView.ItemsSourceProperty, new Binding(nameof(this.Items), mode: BindingMode.OneWay));
LinearItemsLayout linearItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal);
linearItemsLayout.SnapPointsAlignment = SnapPointsAlignment.Start;
linearItemsLayout.SnapPointsType = SnapPointsType.Mandatory;
carousel.ItemsLayout = linearItemsLayout;
this.Children.Add(carousel,0,1);
Expected UI
The easiest way of doing something like that would be to use the Horizontal CollectionView
CollectionView can display its items in a horizontal list by setting its ItemsLayout property to HorizontalList:
When you check the documents it gives a similar example
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="HorizontalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
Alternatively, this layout can also be accomplished by setting the ItemsLayout property to a LinearItemsLayout object, specifying the Horizontal ItemsLayoutOrientation enumeration member as the Orientation property value:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
...
</CollectionView>
This results in a single row list, which grows horizontally as new items are added:
In expression blend I created a sample data source in visual editor. In case of using a listbox I simply drag the collection there and data is automatically shown.
Now, I am interested to retrieve data from datasource from code behind. Is this possible?
There are a couple ways to do this, I will give you the simplest. I have a ListPicker that is bascially the same as a ListBox: Here is my ListPicker markup: Also here is a link
<toolkit:ListPicker Name="lpDrag" Grid.Row="4" Grid.Column="1" Loaded="lptest_Loaded" SelectedIndex="0">
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding name}" />
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
<toolkit:ListPicker.FullModeItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" ></ColumnDefinition>
<ColumnDefinition ></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding name}" FontSize="26" Grid.Column="0" Grid.Row="0"/>
<TextBlock Text="{Binding desc}" TextWrapping="Wrap" FontSize="26" Grid.Column="1" Grid.Row="0" />
</Grid>
</DataTemplate>
</toolkit:ListPicker.FullModeItemTemplate>
</toolkit:ListPicker>
Here is the code behind:
lpDrag.ItemsSource = //Whatever your datasource is
Does anyone have the xaml to get the look and feel of this UI?
This is one way we can do your UI:
<ListBox x:Name="contentList" SelectionChanged="OnFileHit">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Marc Boyer" FontSize="{StaticResource PhoneFontSizeLarge}"/>
<TextBlock Text="Inviation check this out here" Grid.Row="1" FontSize="{StaticResource PhoneFontSizeMedium}" Foreground="GreenYellow"/>
<TextBlock Text="When: Thursday 9 PM" Grid.Row="2" FontSize="{StaticResource PhoneFontSizeNormal}" Opacity="0.5"/>
<TextBlock Text="9.45" HorizontalAlignment="Right" Grid.Row="0" Grid.Column="1" FontSize="{StaticResource PhoneFontSizeNormal}"/>
<Image Grid.Row="1" Grid.Column="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
u Should use panorama and pivot pages to get this kinda UI. Its not very difficult to design such UI but i currently don't have a similar looking screen. probably this link might help u better.
http://www.silverlightshow.net/items/Windows-Phone-7-Part-5-Panorama-and-Pivot-controls.aspx
and also this
http://windowsphonegeek.com/articles/WP7-Navigation-in-depth--Navigation-controls
I found this cool templates that I think others will find it useful.
http://wp7designtemplates.codeplex.com/
the page and tabs are done using the pivot control, there is a template you can choose when you create a new project that has it in by default and also shows how you can create custom list items
I have the following XAML markup in a WP7 UserControl. My problem is that when my ListBox has more items than will fit on a page it will not scroll properly. I can scroll the list by panning upwards with my finger but as soon as I remove my finger it jumps back to the top of the list (if the list is very long then the scrolling will not even work to this limited extent).
I have tried numerous different layouts with no success e.g. Wrapping ListBox in ScrollViewer, utilising StackPanel instead of Grid, removing the WrapPanel and replacing it with a grid.
Other similar questions suggested removing StackPanel (which I did but made no difference) or using ScrollViewer (which did not work).
The Page that hosts the UserControl uses a GestureListener - I removed that and it still made no difference.
<Grid x:Name="LayoutRoot"
Background="SteelBlue">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--<TextBlock Grid.Row="0"
Text="Search"
Style="{StaticResource PhoneTextTitle2Style}" />-->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Search Type"
Grid.Column="0"
VerticalAlignment="Center" />
<RadioButton Content="RMB/RSD"
Grid.Column="1"
IsChecked="{Binding Path=SearchType, Converter={StaticResource enumBooleanConverter}, ConverterParameter=RMB, Mode=TwoWay}" />
<RadioButton Content="Name"
Grid.Column="2"
IsChecked="{Binding Path=SearchType, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Name, Mode=TwoWay}" />
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Search Term"
Grid.Column="0"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Text="{Binding SearchTerm, Mode=TwoWay}"
InputScope="{Binding SearchTermInputScope}">
<i:Interaction.Behaviors>
<b:SelectAllOnFocusBehavior />
</i:Interaction.Behaviors>
</TextBox>
</Grid>
<Button Grid.Row="2"
Content="Find"
cmd:ButtonBaseExtensions.Command="{Binding FindDeliveryPointsCommand}" />
<ListBox Grid.Row="3"
ItemsSource="{Binding SearchResults}"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:WrapPanel Orientation="Horizontal"
Width="480"
Background="{Binding RMB, Converter={StaticResource alternateColorConverter}}">
<TextBlock Text="{Binding RMB}"
FontSize="26"
Foreground="Navy"
Padding="5"
Width="60" />
<TextBlock Text="{Binding HouseholdName}"
FontSize="26"
Foreground="Navy"
Padding="5"
Width="420" />
<TextBlock Text="{Binding StreetWithRRN}"
FontSize="26"
Foreground="Navy"
Padding="5" />
<TextBlock Text="{Binding Street.Locality.Name}"
FontSize="26"
Foreground="Navy"
Padding="5" />
</toolkit:WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Specify ListBox.Height - something like Height="200". As it is now, ListBox expands automatically to accomodate all loaded items and it grows out of the screen. As a result you get large page with no scroller.
When you add ListBox.Height, the ListBox area won't grow. Instead ListBox ScrollViewer will be activated and you'll get the effect you need.
I use databinding when the ListBox's Height changed depending on the other controls on the page.
<StackPanel x:Name="ContentPanel" Grid.Row="1">
<ListBox x:Name="LstSample" Height="{Binding ElementName=ContentPanel, Path=ActualHeight}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImagePath}" Stretch="None"/>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" FontSize="45"/>
<TextBlock Text="{Binding Group}" FontSize="25"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>