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;
}
}
}
{
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; }
}
{
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="马达加斯加"},
};
}
}
{
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>
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拥有相同或者类似的属性时才有最好的效果,下次继续扩展。
半路和尚 by 超时空饭盒 is licensed under a Creative Commons 署名-非商业性使用-相同方式共享 3.0 Unported License.
基于halfwaymonk.cnblogs.com上的作品创作。