Silverlight-TabControl扩展

TabControl是平常用的比较多的布局控件,虽然它是继承自ItemsControl,但是它的ItemsSource实在是很不好用,谁用谁知道。

prism里为TabControl提供了TabControlRegionAdapter和TabControlRegionSyncBehavior,参考其部分实现方式让我们也来实现个TabControl的扩展来更好的MVVM。

看代码:

public class TabControlExtensions
{
public static IEnumerable GetItemsSource(DependencyObject d)
{
return (IEnumerable)d.GetValue(ItemsSourceProperty);
}

public static void SetItemsSource(DependencyObject d, IEnumerable value)
{
d.SetValue(ItemsSourceProperty, value);
}

public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.RegisterAttached(
"ItemsSource", typeof(IEnumerable), typeof(TabControl),
new PropertyMetadata(OnItemsSourceChanged));

private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var source
= d as TabControl;
var items
= e.NewValue as IEnumerable;

source.Items.Clear();

if (items != null)
{
var headerTemplate
= GetHeaderTemplate(source);
var contentTemplate
= GetContentTempalte(source);

foreach (var item in items)
{
var tabItem
= new TabItem
{
DataContext
= item,
Header
= item,
HeaderTemplate
= headerTemplate,
Content
= item,
ContentTemplate
= contentTemplate,
};
source.Items.Add(tabItem);
}
}
}



public static DataTemplate GetHeaderTemplate(DependencyObject d)
{
return (DataTemplate)d.GetValue(HeaderTemplateProperty);
}

public static void SetHeaderTemplate(DependencyObject d, DataTemplate value)
{
d.SetValue(HeaderTemplateProperty, value);
}

public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.RegisterAttached(
"HeaderTemplate", typeof(DataTemplate), typeof(TabControl),
new PropertyMetadata(OnHeaderTemplateChanged));

private static void OnHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var source
= d as TabControl;
var template
= e.NewValue as DataTemplate;

foreach (TabItem item in source.Items)
{
item.HeaderTemplate
= template;
}
}


public static DataTemplate GetContentTempalte(DependencyObject d)
{
return (DataTemplate)d.GetValue(ContentTempalteProperty);
}

public static void SetContentTempalte(DependencyObject d, DataTemplate value)
{
d.SetValue(ContentTempalteProperty, value);
}

public static readonly DependencyProperty ContentTempalteProperty =
DependencyProperty.Register(
"ContentTempalte", typeof(DataTemplate), typeof(TabControl),
new PropertyMetadata(OnContentTempalteChanged));

private static void OnContentTempalteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var source
= d as TabControl;
var template
= e.NewValue as DataTemplate;

foreach (TabItem item in source.Items)
{
item.ContentTemplate
= template;
}
}
}

扩展类TabControlExtensions提供了三个附加属性:

ItemsSource用于设置TabControl的数据源(摒弃自身的ItemsSource不用了)。

HeaderTemplate和ContentTempalte方便设置数据的显示模板(ItemsControl也有ItemTemplate属性,为了清晰,此处就单独拎出来了)。

在三个回调方法里的操作很简单,一看就明白。

来个Model类:

public class Animal
{
public string Name { get; set; }
public int Count { get; set; }
public string From { get; set; }
}

再来个简单的ViewModel类:

public class Zoo
{
public IEnumerable<Animal> Animals { get; private set; }

public Zoo()
{
this.Animals = new List<Animal>
{
new Animal{Name="斑马",Count=10,From="塞伦盖提"},
new Animal{Name="企鹅",Count=23,From="加拉帕戈斯"},
new Animal{Name="环尾狐猴",Count=8,From="马达加斯加"},
};
}
}

看下Xaml里的具体设置和最后的效果:  

<UserControl x:Class="TabControlExtensions.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk
="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:local
="clr-namespace:TabControlExtensions">

<UserControl.DataContext>
<local:Zoo/>
</UserControl.DataContext>

<UserControl.Resources>
<DataTemplate x:Key="HeaderTempalte">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate x:Key="ContentTemplate">
<StackPanel>
<TextBlock Text="{Binding Count,StringFormat='数量:\{0\}'}"/>
<TextBlock Text="{Binding From,StringFormat='来自:\{0\}'}"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White">
<sdk:TabControl Margin="30"
local:TabControlExtensions.ItemsSource
="{Binding Animals}"
local:TabControlExtensions.HeaderTemplate
="{StaticResource HeaderTempalte}"
local:TabControlExtensions.ContentTempalte
="{StaticResource ContentTemplate}"/>
</Grid>
</UserControl>

只要想的到,其实一切都很简单。

另外现在的方式只能在ItemsSource里的每个Item拥有相同或者类似的属性时才有最好的效果,下次继续扩展。

posted @ 2011-06-28 22:57  超时空饭盒  阅读(2446)  评论(8编辑  收藏  举报