Virtualize the loading of Windows 8 XAML controls within a grid - windows-runtime

I have a Window 8 RT store application (XAML/C#).
I have a form with a grid as the main component. That grid has 50 rows and each row has a TextBox. The grid is wrapped in a scrollviewer:
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
...50 rows
</Grid.RowDefinitions>
<TextBox Grid.Row="0" />
<TextBox Grid.Row="1" />
<TextBox Grid.Row="2" />
...
<TextBox Grid.Row="50" />
</Grid>
</ScrollViewer>
When this form is loaded there is a notable pause while the page is loaded, I guessing this is because the page is being drawn.
What is the best way to speed this load process up? Can I virtualize the loading of the grid/Textboxes?
The slowness is notable once the application is running on a Windows Surface tablet, it's not bad on my design PC but that is obviously much more powerful.
Thanks in advance.

You can use a ListView instead of the Grid in a ScrollViewer since that supports virtualization by default. Other than that - it might be nice to have some nicer user experience than a scary long list of TextBoxes to fill - maybe break up your form in multiple pages or use a FlipView to flip between groups of fields.
*EDIT - example
XAML
<Page
x:Class="App10.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App10"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate
x:Key="TextFieldTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition
Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Text="{Binding Label}" />
<TextBox
Text="{Binding Value, Mode=TwoWay}"
Grid.Row="1" />
</Grid>
</DataTemplate>
<DataTemplate
x:Key="BoolFieldTemplate">
<CheckBox
Content="{Binding Label}"
IsChecked="{Binding Value, Mode=TwoWay}" />
</DataTemplate>
<local:FieldTemplateSelector
x:Key="FieldTemplateSelector"
TextTemplate="{StaticResource TextFieldTemplate}"
BoolTemplate="{StaticResource BoolFieldTemplate}" />
</Page.Resources>
<Grid
Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ListView
x:Name="lv"
ItemTemplateSelector="{StaticResource FieldTemplateSelector}" />
</Grid>
</Page>
C#
using System.Collections.Generic;
using App10.Common;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace App10
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.lv.ItemsSource =
new List<object>(
new object[]
{
new BoolFieldViewModel { Label = "Some bool field" },
new TextFieldViewModel { Label = "Some text field" },
new TextFieldViewModel { Label = "Some text field" },
new BoolFieldViewModel { Label = "Some bool field" },
new BoolFieldViewModel { Label = "Some bool field" },
new TextFieldViewModel { Label = "Some text field" },
});
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
public abstract class FieldViewModel<T> : BindableBase
{
public string Label { get; set; }
#region Value
private T _value;
public T Value
{
get { return _value; }
set { this.SetProperty(ref _value, value); }
}
#endregion
}
public class BoolFieldViewModel : FieldViewModel<bool> { }
public class TextFieldViewModel : FieldViewModel<string> { }
public class FieldTemplateSelector : DataTemplateSelector
{
public DataTemplate BoolTemplate { get; set; }
public DataTemplate TextTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item is BoolFieldViewModel) return BoolTemplate;
if (item is TextFieldViewModel) return TextTemplate;
return base.SelectTemplateCore(item, container);
}
}
}

Related

Bindings not set for items not visible

Sorry if this is a dumb question. I am maintaining this crazy Windows Phone 8.1 RT dynamic app that I didn't write. It loads up a whole bunch of stuff to the DataContext. Things that aren't visible on the screen don't seem to get their DataContext. When I navigate away from the form the event fires. What do I need to do to fix that? Even when it scrolls into view it doesn't load. If I scoll up and click the back button I see the field populate before it goes to the previous page.
Edit - Here is some code:
<DataTemplate x:Key="com.somecompany.BarcodeboxRenderer">
<Grid HorizontalAlignment="Stretch" DataContext="{Binding Item1}">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}" HorizontalAlignment="Stretch" Style="{StaticResource labelstyle}" Grid.Row="0" />
<somecompany:BarcodeBox IsReadOnly="{Binding DisplayOnly}" somecompany:DynamicDataBindingPath.BindingPath="{Binding FieldId}" Grid.Row="1" />
</Grid>
</DataTemplate>
That calls this but only if it's visible:
public sealed class DynamicDataBindingPath:FrameworkElement
{
public static readonly DependencyProperty BindingPathProperty = DependencyProperty.RegisterAttached("BindingPath", typeof(string), typeof(DynamicDataBindingPath), new PropertyMetadata("", OnBindingPathPropertyChanged));
public static string GetBindingPath(FrameworkElement target)
{
try
{
return (string)target.GetValue(BindingPathProperty);
}
catch (Exception)
{
return string.Empty;
}
}
public static void SetBindingPath(FrameworkElement target, string value)
{
target.SetValue(BindingPathProperty, value);
target.Loaded += Target_Loaded;
}
private static void Target_Loaded(object sender, RoutedEventArgs e) {
var target = (FrameworkElement)sender;
if (target is ...) { ... }
else if (target is DatePicker)
{
int startingletterindex = value.IndexOf('.') + 1;
string pathtobindto = "obj." + Char.ToUpper(value[startingletterindex]) + value.Substring((startingletterindex + 1));
Binding newbind = new Binding();
newbind.Path = new PropertyPath(pathtobindto);
var contextsrc = findRealDataContext(target);
newbind.Source = contextsrc.DataContext;
newbind.Mode = BindingMode.TwoWay;
(target as DatePicker).SetBinding(DatePicker.DateProperty, newbind);
}
else if (...)
}
I turned of ListView Virtualization and it works now. I don't need it because there will never be more than a handful of rows.

MVVMcross Command Binding fire Exception

I experience an issue when i try to use a command to open a Second View Model V4.0.Beta5.
I followed the Exemple described in N+1 Video series https://www.youtube.com/playlist?list=PLR6WI6W1JdeYSXLbm58jwAKYT7RQR31-W
First ViewModel
public class FirstViewModel
: MvxViewModel
{
private string _hello = "Hello MvvmCross";
public string Hello
{
get { return _hello; }
set
{
_hello = value;
RaisePropertyChanged(() => Hello);
}
}
private Cirrious.MvvmCross.ViewModels.MvxCommand _goSecondViewCommand;
public System.Windows.Input.ICommand GoSecondViewCommand
{
get
{
_goSecondViewCommand = _goSecondViewCommand ??
new Cirrious.MvvmCross.ViewModels.MvxCommand(DoGoSecondView);
return _goSecondViewCommand;
}
}
private void DoGoSecondView()
{
base.ShowViewModel<SecondViewModel>();
}
}
Second View model
public class SecondViewModel :MvxViewModel
{
private string _hello2 = "Hello2 MvvmCross";
public string Hello2
{
get { return _hello2; }
set
{
_hello2 = value;
RaisePropertyChanged(() => Hello2);
}
}
}
First View
<views:MvxWindowsPage
x:Class="TestCommand.UWP.Views.FirstView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestCommand.UWP"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:Cirrious.MvvmCross.WindowsUWP.Views"
mc:Ignorable="d">
<Grid>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="70,92,0,0" TextWrapping="Wrap" Text="FirstView" VerticalAlignment="Top" Width="223"/>
<Button x:Name="button" Command="{Binding GoSecondViewCommand}" Content="Button" HorizontalAlignment="Left" Height="108" Margin="70,346,0,0" VerticalAlignment="Top" Width="223"/>
</Grid>
Second view
<views:MvxWindowsPage
x:Class="TestCommand.UWP.Views.SecondView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestCommand.UWP.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:Cirrious.MvvmCross.WindowsUWP.Views"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid />
Setup Class:
public class Setup : MvxWindowsSetup
{
public Setup(Frame rootFrame) : base(rootFrame)
{
}
protected override IMvxApplication CreateApp()
{
return new TestCommand.Core.App();
}
}
If you want you can download the solution Here:
https://onedrive.live.com/redir?resid=A5D9789788DE33CB!36079&authkey=!AKs9nsG28iI6nQQ&ithint=file%2czip.
The possible reason is you don't use Setup correctly in your UWP app, here is what I do to make this work:
1) Create two ViewModels in the UWP app: FirstViewModel and SecondViewModel
2) Create a Setup class in Setup.cs file:
public class Setup : MvxWindowsSetup
{
public Setup(Frame rootFrame) : base(rootFrame)
{
}
protected override IMvxApplication CreateApp()
{
return new AppSetup();
}
}
public class AppSetup : MvxApplication
{
public override void Initialize()
{
RegisterAppStart<FirstViewModel>();
}
}
3) FirstView.xaml:
<StackPanel>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="70,92,0,0" TextWrapping="Wrap" Text="FirstView" VerticalAlignment="Top" Width="223"/>
<TextBlock Height="50" Text="{Binding Hello}" />
<Button x:Name="button" Command="{Binding GoSecondViewCommand}" Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="223" Height="50" />
</StackPanel>
4) SecondView.xaml:
<StackPanel>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="70,92,0,0" TextWrapping="Wrap" Text="SecondView" VerticalAlignment="Top" Width="223"/>
<TextBlock Height="50" Text="{Binding Hello2}" />
</StackPanel>
5) In App.xaml.cs file, make the following changes in OnLaunched method:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
......
if (rootFrame.Content == null)
{
var setup = new Setup(rootFrame);
setup.Initialize();
var start = Mvx.Resolve<IMvxAppStart>();
start.Start();
}
// Ensure the current window is active
Window.Current.Activate();
}
By the way, the MvvmCross version is 3.5.1
Check the Completed sample on Github
Update for exception in OnNavigationFailed method:
Please comment this line in FirstView and SecondView's code behind:
ViewModel = new FirstViewModel();
ViewModel = new SecondViewModel();
The MvvmCross has set the ViewModel automatically.

Design Time Windows Store App with JSON

I am trying to create a windows store app using a Blank Windows 8 store App and can't get basic Design time working. I am obviously missing something simple, but with the research I have done don't see the difference
Here is my MainPage.xaml
<Page
x:Class="TestHubDataBinding.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestHubDataBinding"
xmlns:data="using:TestHubDataBinding.ViewModels"
xmlns:repo="using:TestHubDataBinding.Repo"
d:DataContext="{Binding Source={d:DesignData Source=Repo/VacationData.json, IsDesignTimeCreatable=True, Type=data:VacationViewModel}}"
xmlns:viewModel="using:TestHubDataBinding.Repo"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Hub x:Name="MainHub" d:DataContext="{ Binding VacationViewModel[0], Source={d:DesignData Source=Repo/VacationData.json, IsDesignTimeCreatable=True, Type=repo:VacationDataSource}}">
<HubSection x:Name="VacationItemsSection" Width="500" Height="500" x:Uid="VacationItemsSection" Header="Vacations">
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Style="{StaticResource SubheaderTextBlockStyle}" Grid.Row="1" Margin="0,10,0,0" TextWrapping ="Wrap"
Text="{Binding VacationViewModel[0].Name, Mode=OneWay}" />
</Grid>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
Here is my View Model:
[DataContract]
public class VacationViewModel
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<string> VacationsList { get; set; }
}
Here is my JSON:
[
{
"Name":"Virginia Beach",
"VItems":
[
{
"Name":"Shorts (Plad)","Value":"2"
}
]
}
, {
"Name":"Orlando Florida",
"VItems":
[
{
"Name":"Shorts (Plad)","Value":"2"
}
]
}
]
And Here is my DataSource:
public class VacationDataSource
{
private readonly ObservableCollection<VacationViewModel> _vacations = new ObservableCollection<VacationViewModel>();
public ObservableCollection<VacationViewModel> Vacations
{
get { return _vacations; }
}
public async Task<TModel> ToObject<TModel>()
{
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///DataModel/Repo/VacationData.json"));
var json = await FileIO.ReadTextAsync(file);
return Deserialize<TModel>(json);
}
public string ToJson<TObject>(TObject model)
{
return Serialize(model);
}
private static string Serialize<TObject>(TObject model, JsonSerializerSettings settings = null)
{
if (settings == null)
{
settings = new JsonSerializerSettings();
}
return JsonConvert.SerializeObject(model, settings);
}
private static TModel Deserialize<TModel>(string jsonString, JsonSerializerSettings settings = null)
{
if (settings == null)
{
settings = new JsonSerializerSettings();
}
return JsonConvert.DeserializeObject<TModel>(jsonString, settings);
}
}
It seems that the data will return for runtime, but design time just does not want to work.
Thanks

MainviewModel windows phone 8

This is the class where I'm trying to load the data
PAGE2 XAML
<xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Margin="0,10,0,0" Grid.Row="1">
<phone:LongListSelector x:Name="MainLongListSelector" Margin="10,2,0,0" ItemsSource="{Binding Items2}" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Height="154">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="20" Margin="0,0,0,538" Height="150"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
MainViewModel
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Package_Tracker_P.Resources;
using System.Collections.Generic;
using Windows.Storage;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Text.RegularExpressions;
namespace Package_Tracker_P.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
public static List<Car> carlist = new List<Car>();
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();
this.Items2 = new ObservableCollection<ItemViewModel>();
}
/// <summary>
/// A collection for ItemViewModel objects.
/// </summary>
public ObservableCollection<ItemViewModel> Items { get; private set; }
public ObservableCollection<ItemViewModel> Items2 { get; private set; }
private string _sampleProperty = "Sample Runtime Property Value";
/// <summary>
/// Sample ViewModel property; this property is used in the view to display its value using a Binding
/// </summary>
/// <returns></returns>
public string SampleProperty
{
get
{
return _sampleProperty;
}
set
{
if (value != _sampleProperty)
{
_sampleProperty = value;
NotifyPropertyChanged("SampleProperty");
}
}
}
/// <summary>
/// Sample property that returns a localized string
/// </summary>
public string LocalizedSampleProperty
{
get
{
return AppResources.SampleProperty;
}
}
public bool IsDataLoaded
{
get;
private set;
}
/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public async void LoadData(Car toyota)
{
// Sample data; replace with real data
carlist.Add(toyota);
this.Items.Add(new ItemViewModel() { ID = (Items.Count.ToString()), LineOne = toyota.status, LineTwo = "", LineThree = "" });
this.IsDataLoaded = true;
//await openfile();
await IO.WriteToFile();
}
public async void LoadData()
{
try
{
stuff();
}
catch (Exception ex)
{
MessageBox.Show("Error Loading Data");
}
}
public void stuff()
{
this.Items2.Add(new ItemViewModel() { ID = (Items2.Count.ToString()), LineOne = "Auto Detect", LineTwo = "", LineThree = "" });
this.IsDataLoaded = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
The problem is is not loading the data for PAGE2. It is loading it for the main page using items1. While the app is loading it calls LoadData() and that call stuff() which is adding data to items2. It is correctly
binded in the xaml file for PAGE TWO in the textblock. Am I missing something?
i think the main problem with this code is that you have not set the datacontext of the page 2
like if you are using MVVM light then
DataContext = {Binding MainViewModel,Source="{StaticResource Locator}}"

Using a progress indicator that gets hidden within a Panorama control is causing the panorama item to just to 1st one

I have a really strange and annoying issue on my WP8 app.
It's using a Panorama control to view items that it downloads from the Net. It has a view that is displayed whilst it's downloading content but then gets collapsed after the content has completed loading.
When the "loading" view is collapsed I'm finding that the Panorama control jumps back to the first item in the control regardless of what item you have selected.
I have the following very basic test code that demonstrates the issue.
XAML:
<phone:PhoneApplicationPage
x:Class="Wp8.GUI.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="clr-namespace:Wp8.Gui.Converters"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Grid.Resources>
<phone:Panorama ItemsSource="{Binding PanoramaItems}">
<phone:Panorama.HeaderTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Title}" />
</Grid>
</DataTemplate>
</phone:Panorama.HeaderTemplate>
<phone:Panorama.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel x:Name="Visible1" Visibility="{Binding ShowFirst, Converter={StaticResource BooleanToVisibilityConverter},ConverterParameter=True}" >
<ProgressBar IsIndeterminate="True" />
<TextBlock Text="ShowFirst" />
</StackPanel>
<StackPanel x:Name="Visible2" Visibility="{Binding ShowFirst, Converter={StaticResource BooleanToVisibilityConverter},ConverterParameter=False}" >
<TextBlock Text="Show Second" />
</StackPanel>
</Grid>
</DataTemplate>
</phone:Panorama.ItemTemplate>
</phone:Panorama>
</Grid>
</phone:PhoneApplicationPage>
The VM and Code Behind is as follows:
namespace Wp8.GUI
{
public class PanItemVm : INotifyPropertyChanged
{
private readonly string _title;
private bool _showFirst = true;
public PanItemVm()
{
_title = "Control";
}
public PanItemVm(string title)
{
_title = title;
}
public string Title { get { return _title; } }
public bool ShowFirst
{
get { return _showFirst; }
set
{
_showFirst = value;
RaisePropertyChanged("ShowFirst");
}
}
private void RaisePropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class PanItemVm2 : PanItemVm
{
public PanItemVm2() : base ("Items")
{
Task.Run(() => Task.Delay(TimeSpan.FromSeconds(5)))
.ContinueWith(t => ShowFirst = false,
TaskScheduler.FromCurrentSynchronizationContext());
}
}
public class TestVm : INotifyPropertyChanged
{
public IEnumerable<PanItemVm> PanoramaItems
{
get {
return Enumerable.Range(0, 2)
.Select(i => i == 0 ?
new PanItemVm() : new PanItemVm2()); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
DataContext = new TestVm();
}
}
}
If you run up the code in an emulator and then flick to Item2 in the Panorama. After 5 seconds it'll flick back to the page marked "Control".
In this test code I can get around the problem by either
a) Changing the StackPanel that the ProgressIndicator is contained in to a Grid
b) Removing the ProgressIndicator
Neither of these solutions work for my proper project however but if I remove Visibility code that uses the BooleanToVisibilityConverter then it doesn't flick back.
Does anybody have any ideas what might be causing this?
I can post the entire sample code if that's useful.
Thanks
--- EDIT ---
Here is the code for the BooleanToVisibilityConverter
using System.Windows;
using System.Windows.Data;
namespace Wp8.Gui.Converters
{
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is bool)
{
bool visibilityValue = true;
if(parameter != null)
{
if(parameter is string)
{
bool.TryParse((string)parameter, out visibilityValue);
}
}
return (bool)value == visibilityValue ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Visible;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
}
I've been having the same problem. I have a Panorama (modified to fill the full screen) that I'm using to display pictures in a carousel. I have to turn the pictures on/off based on Panorama position to keep the memory low. However, whenever a picture loads, the panorama returns to the default item... the first item.
So I took a hint from another question and went to look at the source code for Panorama. While you can't see the current code, you can see what Panorama was when it was part of the WP Toolkit. It seems that anytime there is a change in size of the panorama, the internal scrollviewer is reset.
void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
// clip to control layout
LayoutRoot.SetValue(Panel.ClipProperty, new RectangleGeometry() { Rect = new Rect(0, 0, this.Width, this.Height) });
// reset scroll viewer
Dispatcher.BeginInvoke(() =>
{
ScrollView.Invalidate(false);
});
}
OK. That was a clue. So I played around with my itemtemplate (my header is non-existent) trying to see what was changing size. SOMETHING was changing size... not sure what. So I wrapped everything in a Grid and hardcoded the Width/Height/MaxWidth/MaxHeight to be equal to the Screen Height/Width. They are bound to calculated values in my viewmodel that change according to device orientation.
<controls:PanoramaFullScreen.ItemTemplate>
<DataTemplate>
<Grid Width="{Binding LayoutWidth}"
MaxWidth="{Binding LayoutWidth}"
Height="{Binding LayoutHeight}"
MaxHeight="{Binding LayoutHeight}">
{rest of stuff}
</Grid>
</DataTemplate>
It works! No more switching back to item one!
So I suspect your code is changing the overall height/width of a PanoramaItem, which is in turn changing the Panorama size and resetting the internal scrollviewer.