If you decided to use a Panorama control in your Windows Phone application, then you will be as disappointed as I am to discover Microsoft remove it from the Universal Windows Platform.

With a quick search on the web, you see it should be easy to replace with a Hub control.

But, surprise, the convenient ItemsSource property has been removed. In a panorama it was easy to bind a data source to generate one panorama section per item. You can’t natively do that with a Hub.windows-phone-7-panoramaDear Microsoft, bringing some cool stuff from Linux is great, but please consider keeping convenience for what is already awesome in your development environment: DataBinding. I would even say it’s one of the killer feature of C#/XAML applications.

Anyway, I will describe a DynamicHub implementation, to get the ability to generate one hub section per item in your data source.

First re-create your own DependencyObject. Then when the interesting dependency changes, iterate on your data and create one hub section per item.

[cc lang=”csharp”]
public class DynamicHub : DependencyObject
{
public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.RegisterAttached(
“HeaderTemplate”,
typeof(DataTemplate),
typeof(DynamicHub), new PropertyMetadata(null, HeaderTemplateChanged)
);

private static void HeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var hub = d as Hub;
if (hub == null) return;
var template = e.NewValue as DataTemplate;
if (template == null) return;
foreach (var hubSection in hub.Sections)
{
hubSection.HeaderTemplate = template;
}
}
public static void SetHeaderTemplate(UIElement element, DataTemplate value)
{
element.SetValue(HeaderTemplateProperty, value);
}

public static DataTemplate GetHeaderTemplate(UIElement element)
{
return element.GetValue(HeaderTemplateProperty) as DataTemplate;
}

public static readonly DependencyProperty SectionTemplateProperty = DependencyProperty.RegisterAttached(
“SectionTemplate”,
typeof(DataTemplate),
typeof(DynamicHub), new PropertyMetadata(null, SectionTemplateChanged)
);

private static void SectionTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var hub = d as Hub;
if (hub == null) return;
var template = e.NewValue as DataTemplate;
if (template == null) return;
foreach (var hubSection in hub.Sections)
{
hubSection.ContentTemplate = template;
}
}
public static void SetSectionTemplate(UIElement element, DataTemplate value)
{
element.SetValue(SectionTemplateProperty, value);
}

public static DataTemplate GetSectionTemplate(UIElement element)
{
return element.GetValue(SectionTemplateProperty) as DataTemplate;
}

public static readonly DependencyProperty DataSourceProperty = DependencyProperty.RegisterAttached(
“DataSource”,
typeof(object),
typeof(DynamicHub),
new PropertyMetadata(null, DataSourceChanged)
);

private static void DataSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var data = e.NewValue as IEnumerable;
var hub = d as Hub;
var template = GetSectionTemplate(hub);
var header = GetHeaderTemplate(hub);
if (data == null || hub == null) return;

hub.Sections.Clear();
foreach (var section in data)
{
var sect = new HubSection { DataContext = section, ContentTemplate = template, HeaderTemplate = header };
var hubData = section as IHubData;
if (hubData != null)
{
sect.Header = hubData.Header;
}

hub.Sections.Add(sect);
}
}

public static void SetDataSource(UIElement element, object value)
{
element.SetValue(DataSourceProperty, value);
}

public static object GetDataSource(UIElement element)
{
return element.GetValue(DataSourceProperty);
}
private interface IHubData
{
object Header { get; }
}
}
[/cc]

Here is a XAML example to use it:

[cc lang=”csharp”]


[/cc]

And a data template to display it:

[cc lang=”csharp”]











[/cc]

Hope it helps, full demo code is on GitHub.

Leave a Reply

Your email address will not be published. Required fields are marked *