Paolo Iommarini
Paolo Iommarini

Reputation: 259

Windows Phone 8: Add FrameworkElement to PanoramaItem from code behind

When I add FrameworkElements to a PanoramaItem from code behind the panorama "selects" the panoramaItem, causing a really bad user experience.

I made a small test project where the problem is reproduced.

Tha MainPage contains just a panorama with three items:

<Grid x:Name="LayoutRoot" Background="Transparent">
    <phone:Panorama Name="m_Panorama">
        <phone:PanoramaItem Header="Item 1" 
                            Name="m_Item1">
            <StackPanel Orientation="Vertical" Name="m_Stack1">
            </StackPanel>
        </phone:PanoramaItem>
        <phone:PanoramaItem Header="Item 2" 
                            Name="m_Item2">
            <StackPanel Orientation="Vertical" Name="m_Stack2">
            </StackPanel>
        </phone:PanoramaItem>
        <phone:PanoramaItem Header="Item 3" 
                            Name="m_Item3">
            <StackPanel Orientation="Vertical" Name="m_Stack3">
            </StackPanel>
        </phone:PanoramaItem>            
    </phone:Panorama>
</Grid>

The code behind uses a DispatcherTimer to start adding the elements to the PanoramaItems:

public partial class MainPage : PhoneApplicationPage
{
  public MainPage()
  {
    InitializeComponent();
  }

  protected override void OnNavigatedTo(NavigationEventArgs e)
  {
    base.OnNavigatedTo(e);
    if (e.NavigationMode == NavigationMode.New){
      StartDelayed(UpdateItem1, 1000);
      StartDelayed(UpdateItem2, 1000);
      StartDelayed(UpdateItem3, 1000);
    }
  }

  private void AddTextblock(StackPanel stackPanel, string text, bool animate)
  {
    TextBlock tb = new TextBlock();
    tb.Text = text;
    stackPanel.Children.Add(tb);

    if (animate){
      tb.Measure(new Size(double.MaxValue, double.MaxValue));
      tb.UpdateLayout();

      Storyboard sb = new Storyboard();
      DoubleAnimation anim = new DoubleAnimation();
      anim.Duration = new Duration(TimeSpan.FromMilliseconds(500));
      anim.From = 0;
      anim.To = tb.DesiredSize.Width;
      sb.Children.Add(anim);
      Storyboard.SetTarget(anim, tb);
      Storyboard.SetTargetProperty(anim, new PropertyPath("Width"));
      sb.Begin();
    }
  }

  private async void UpdateItem1(object sender, EventArgs e)
  {
    while (true){
      m_Stack1.Children.Clear();
      for (int i=0; i<10; i++){
        await Task.Delay(500);
        AddTextblock(m_Stack1, "This is item 1", false);
      }
    }
  }

  private async void UpdateItem2(object sender, EventArgs e)
  {
    while (true){
      m_Stack2.Children.Clear();
      for (int i=0; i<10; i++){
        await Task.Delay(1000);
        AddTextblock(m_Stack2, "This is item 2", false);
      }
    }
  }

  private async void UpdateItem3(object sender, EventArgs e)
  {
    while (true){
      m_Stack3.Children.Clear();
      for (int i=0; i<10; i++){
        await Task.Delay(1500);
        AddTextblock(m_Stack3, "This is item 3", false);
      }
    }
  }

  private static void StartDelayed(EventHandler handler, int milliseconds)
  {
    DispatcherTimer timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromMilliseconds(milliseconds);
    if (handler != null)
      timer.Tick += new EventHandler(handler);
    timer.Tick += new EventHandler(OnLoadedTimerTick);
    timer.Start();
  } // StartDelayed

  private static void OnLoadedTimerTick(object sender, EventArgs e)
  {
    DispatcherTimer timer = sender as DispatcherTimer;
    if (timer != null)
      timer.Stop();
  } // OnLoadedTimerTick
}

The problem can be seen if you scroll slowly the panorama: as soon as one item is added to the stack panel the Panorama will reposition to the PanoramaItem containing the added element.

My question is: what am I doing wrong? How can I avoid the panorama to select the panoramaItem?

Upvotes: 2

Views: 257

Answers (1)

Chubosaurus Software
Chubosaurus Software

Reputation: 8161

A quick solution is to enclose the StackPanel in a fixed size container.

For example

<phone:PanoramaItem Header="Item 1" Name="m_Item1">
    <ScrollViewer Height="1024">
        <StackPanel Orientation="Vertical" Name="m_Stack1"/>
    </ScrollViewer>
</phone:PanoramaItem>

What I think is going on is that it is dynamically resizing the element and its container resulting in that jerking motion you see when you scroll horizontally to the next panorama item. And if you want you can bind the height of that ScrollViewer to the height of the screen for optimal use.

Upvotes: 3

Related Questions