OK, finally got time to answer the question. The proposed solution does not require any code behind and only relys on MVVM concepts and data binding.
Conceptionally the Panorama
control is an ItemPresenter (it inherits from ItemsPresenter
), i.e. you can bind the ItemsSource
to a list that contains items that repesent your PanoramaItems
.
To render your PanoramaItem
you will have to provide templates for Panorama.HeaderTemplate
and Panorama.ItemTemplate
. The DataContext
inside the templates is the ViewModel
that represents your PanoramaItem
. If this ViewModel
contains an item list you now can use it to generate the ListBoxes
you were looking for.
And here is the sample ...
ViewModelLocator.cs
using GalaSoft.MvvmLight;
namespace WP7Test.ViewModel
{
public class ViewModelLocator
{
private static MainViewModel _main;
public ViewModelLocator()
{
if (ViewModelBase.IsInDesignModeStatic) {
// Create design time services and viewmodels
} else {
// Create run time services and view models
}
_main = new MainViewModel();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return _main;
}
}
}
}
MainViewModel.cs
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();
if (IsInDesignMode) {
// Code runs in Blend --> create design time data.
} else {
// Code runs "for real"
}
this.LoadData();
}
#region [Items]
public const string ItemsPropertyName = "Items";
private ObservableCollection<ItemViewModel> _items = default(ObservableCollection<ItemViewModel>);
public ObservableCollection<ItemViewModel> Items {
get {
return _items;
}
private set {
if (_items == value) {
return;
}
var oldValue = _items;
_items = value;
RaisePropertyChanged(ItemsPropertyName);
}
}
#endregion
private void LoadData() {
this.Items.Add(new ItemViewModel() { LineOne = "runtime one", LineTwo = "Maecenas praesent accumsan bibendum", LineThree = "Facilisi faucibus habitant inceptos interdum lobortis nascetur pharetra placerat pulvinar sagittis senectus sociosqu" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime two", LineTwo = "Dictumst eleifend facilisi faucibus", LineThree = "Suscipit torquent ultrices vehicula volutpat maecenas praesent accumsan bibendum dictumst eleifend facilisi faucibus" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime three", LineTwo = "Habitant inceptos interdum lobortis", LineThree = "Habitant inceptos interdum lobortis nascetur pharetra placerat pulvinar sagittis senectus sociosqu suscipit torquent" });
foreach (var item in Items) {
for (int i = 0; i < 5; ++i)
item.Items.Add(new ItemViewModel() { LineOne = "Item " + i, LineTwo = "Maecenas praesent accumsan bibendum" });
}
}
}
ItemViewModel.cs
public class ItemViewModel : ViewModelBase
{
public ItemViewModel() {
this.Items = new ObservableCollection<ItemViewModel>();
if (IsInDesignMode) {
// Code runs in Blend --> create design time data.
} else {
// Code runs "for real": Connect to service, etc...
}
}
public override void Cleanup() {
// Clean own resources if needed
base.Cleanup();
}
#region [LineOne]
public const string LineOnePropertyName = "LineOne";
private string _lineOne = default(string);
public string LineOne {
get {
return _lineOne;
}
set {
if (_lineOne == value) {
return;
}
var oldValue = _lineOne;
_lineOne = value;
RaisePropertyChanged(LineOnePropertyName);
}
}
#endregion
#region [LineTwo]
public const string LineTwoPropertyName = "LineTwo";
private string _lineTwo = default(string);
public string LineTwo {
get {
return _lineTwo;
}
set {
if (_lineTwo == value) {
return;
}
var oldValue = _lineTwo;
_lineTwo = value;
RaisePropertyChanged(LineTwoPropertyName);
}
}
#endregion
#region [LineThree]
public const string LineThreePropertyName = "LineThree";
private string _lineThree = default(string);
public string LineThree {
get {
return _lineThree;
}
set {
if (_lineThree == value) {
return;
}
var oldValue = _lineThree;
_lineThree = value;
RaisePropertyChanged(LineThreePropertyName);
}
}
#endregion
#region [Items]
public const string ItemsPropertyName = "Items";
private ObservableCollection<ItemViewModel> _items = default(ObservableCollection<ItemViewModel>);
public ObservableCollection<ItemViewModel> Items {
get {
return _items;
}
private set {
if (_items == value) {
return;
}
var oldValue = _items;
_items = value;
RaisePropertyChanged(ItemsPropertyName);
}
}
#endregion
}
MainPage.xaml
<phone:PhoneApplicationPage
x:Class="WP7Test.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:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{Binding Main, Source={StaticResource Locator}}">
<controls:Panorama Title="my application" ItemsSource="{Binding Items}">
<controls:Panorama.Background>
<ImageBrush ImageSource="PanoramaBackground.png"/>
</controls:Panorama.Background>
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding LineOne}"/>
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:Panorama.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border BorderThickness="0,0,0,1" BorderBrush="White">
<TextBlock Text="{Binding LineTwo}" FontSize="28" TextWrapping="Wrap"/>
</Border>
<Border BorderThickness="0,0,0,1" Margin="0,20" BorderBrush="White">
<TextBlock Text="{Binding LineThree}" TextWrapping="Wrap"/>
</Border>
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding LineOne}" FontSize="24"/>
<TextBlock Text="{Binding LineTwo}" FontSize="18" Margin="24,0,0,5"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
</Grid>
<!--Panorama-based applications should not show an ApplicationBar-->
</phone:PhoneApplicationPage>
Edit - adding additional first panel
Finally I understand what you trying to achive! However, you still need no code behind to do it! You just need a template ... for this Blend does help you as it lets you extract a template for a exiting control ... ok, here are the changes.
First I added a new property to the MainViewModel to show some data:
#region [MainPageProperty]
public const string MainPagePropertyPropertyName = "MainPageProperty";
private string _mainPageProperty = "Facilisi faucibus habitant inceptos interdum lobortis nascetur pharetra placerat pulvinar sagittis senectus sociosqu";
public string MainPageProperty {
get {
return _mainPageProperty;
}
set {
if (_mainPageProperty == value) {
return;
}
_mainPageProperty = value;
RaisePropertyChanged(MainPagePropertyPropertyName);
}
}
#endregion
Then I used Blend to get the template for the Panorama control and inserted it into the controls:Panorama
element.
<controls:Panorama.Template>
<ControlTemplate TargetType="controls:Panorama">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<controlsPrimitives:PanningBackgroundLayer x:Name="BackgroundLayer" HorizontalAlignment="Left" Grid.RowSpan="2">
<Border x:Name="background" Background="{TemplateBinding Background}" CacheMode="BitmapCache"/>
</controlsPrimitives:PanningBackgroundLayer>
<controlsPrimitives:PanningTitleLayer x:Name="TitleLayer" CacheMode="BitmapCache" ContentTemplate="{TemplateBinding TitleTemplate}" Content="{TemplateBinding Title}" FontSize="187" FontFamily="{StaticResource PhoneFontFamilyLight}" HorizontalAlignment="Left" Margin="10,-76,0,9" Grid.Row="0"/>
<controlsPrimitives:PanningLayer x:Name="ItemsLayer" HorizontalAlignment="Left" Grid.Row="1">
<StackPanel Orientation="Horizontal">
<controls:PanoramaItem Header="Main panel" Width="432">
<TextBloc