我想扩展选项卡控件以具有可关闭的选项卡项。
我找到了 Kent 的这个 WPF 解决方案: 在 WPF TabControl 上 - 我可以在选项卡标题旁边添加内容吗?
我在 Blend 中打开了现有 silverlight tabcontrol 的副本。但是,该结构看起来与 WPF 选项卡控件完全不同。我无法将它直接放入 Silverlight 控件模板。
有谁知道我的好资源?
我想扩展选项卡控件以具有可关闭的选项卡项。
我找到了 Kent 的这个 WPF 解决方案: 在 WPF TabControl 上 - 我可以在选项卡标题旁边添加内容吗?
我在 Blend 中打开了现有 silverlight tabcontrol 的副本。但是,该结构看起来与 WPF 选项卡控件完全不同。我无法将它直接放入 Silverlight 控件模板。
有谁知道我的好资源?
我之前也遇到过同样的问题,然后我决定使用扩展的TabControl
. 我不知道我在哪里找到它,但没关系,现在它在我的项目中。
有了这个TabControl
,我可以从 ViewModel 集合中添加或删除项目,我的更改将反映在用户界面上。
MyTabControl.cs
public class MyTabControl : TabControl
{
public MyTabControl()
: base()
{
this.SelectionChanged += OnSelectionChanged;
}
#region Tabs with databinding and templates
/// <summary>
/// Template for a TabItem header
/// </summary>
public DataTemplate TabHeaderItemTemplate
{
get { return (DataTemplate)GetValue(TabHeaderItemTemplateProperty); }
set { SetValue(TabHeaderItemTemplateProperty, value); }
}
public static readonly DependencyProperty TabHeaderItemTemplateProperty =
DependencyProperty.Register("TabHeaderItemTemplate", typeof(DataTemplate), typeof(MyTabControl), new PropertyMetadata(
(sender, e) =>
{
((MyTabControl)sender).InitTabs();
}));
/// <summary>
/// Template for a content
/// </summary>
public DataTemplate TabItemTemplate
{
get { return (DataTemplate)GetValue(TabItemTemplateProperty); }
set { SetValue(TabItemTemplateProperty, value); }
}
public static readonly DependencyProperty TabItemTemplateProperty =
DependencyProperty.Register("TabItemTemplate", typeof(DataTemplate), typeof(MyTabControl), new PropertyMetadata(
(sender, e) =>
{
((MyTabControl)sender).InitTabs();
}));
/// <summary>
/// Source of clr-objects
/// </summary>
public IEnumerable MyItemsSource
{
get
{
return (IEnumerable)GetValue(MyItemsSourceProperty);
}
set
{
SetValue(MyItemsSourceProperty, value);
}
}
public static readonly DependencyProperty MyItemsSourceProperty =
DependencyProperty.Register("MyItemsSource", typeof(IEnumerable), typeof(MyTabControl), new PropertyMetadata(
(sender, e) =>
{
MyTabControl control = (MyTabControl)sender;
INotifyCollectionChanged incc = e.OldValue as INotifyCollectionChanged;
if (incc != null)
{
incc.CollectionChanged -= control.MyItemsSourceCollectionChanged;
}
control.InitTabs();
incc = e.NewValue as INotifyCollectionChanged;
if (incc != null)
{
incc.CollectionChanged += control.MyItemsSourceCollectionChanged;
}
}));
/// <summary>
/// Selected item as object
/// </summary>
public object MySelectedItem
{
get { return (object)GetValue(MySelectedItemProperty); }
set { SetValue(MySelectedItemProperty, value); }
}
// Using a DependencyProperty as the backing store for MySelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MySelectedItemProperty =
DependencyProperty.Register("MySelectedItem", typeof(object), typeof(MyTabControl), new PropertyMetadata(
(sender, e) =>
{
MyTabControl control = (MyTabControl)sender;
if (e.NewValue == null)
control.SelectedItem = null;
else
{
var tab = control.Items.Cast<TabItem>().FirstOrDefault(ti => ti.DataContext == e.NewValue);
if (tab != null && control.SelectedItem != tab)
control.SelectedItem = tab;
}
}));
private void InitTabs()
{
Items.Clear();
if (MyItemsSource != null && MyItemsSource.OfType<object>().Any())
{
int i = 0;
foreach (var item in MyItemsSource)
{
var newitem = new TabItem();
if (TabItemTemplate != null)
newitem.Content = TabItemTemplate.LoadContent();
if (TabHeaderItemTemplate != null)
newitem.Header = TabHeaderItemTemplate.LoadContent();
newitem.DataContext = item;
Items.Add(newitem);
}
VisualStateManager.GoToState(this, "Normal", true);
}
else VisualStateManager.GoToState(this, "NoTabs", true);
}
private void MyItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
if (e.NewStartingIndex > -1)
{
foreach (var item in e.NewItems)
{
var newitem = new TabItem();
if (TabItemTemplate != null)
newitem.Content = TabItemTemplate.LoadContent();
if (TabHeaderItemTemplate != null)
newitem.Header = TabHeaderItemTemplate.LoadContent();
newitem.DataContext = item;
Items.Add(newitem);
}
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
if (e.OldStartingIndex > -1)
{
var ti = (TabItem)this.Items[e.OldStartingIndex];
Items.RemoveAt(e.OldStartingIndex);
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)
{
Items.RemoveAt(e.OldStartingIndex);
var newitem = new TabItem();
if (TabItemTemplate != null)
newitem.Content = TabItemTemplate.LoadContent();
if (TabHeaderItemTemplate != null)
newitem.Header = TabHeaderItemTemplate.LoadContent();
newitem.DataContext = e.NewItems[0];
Items.Add(newitem);
Items.Insert(e.NewStartingIndex, newitem);
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset)
{
InitTabs();
}
}
#endregion
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var si = e.AddedItems.Cast<TabItem>().FirstOrDefault();
if (si != null)
this.MySelectedItem = si.DataContext;
else this.MySelectedItem = null;
}
}
主页.xaml
<my:MyTabControl MyItemsSource="{Binding Items}" MySelectedItem="{Binding SelectedITem}">
<my:MyTabControl.TabHeaderItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" VerticalAlignment="Center"/>
<Button Content="X" Margin="3" Width="20" Height="20" Grid.Column="1"
Command="{Binding RequestCloseCommand}"/>
</Grid>
</DataTemplate>
</my:MyTabControl.TabHeaderItemTemplate>
<my:MyTabControl.TabItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding Content}"/>
</DataTemplate>
</my:MyTabControl.TabItemTemplate>
</my:MyTabControl>
请注意,属性被称为MyItemsSource
and MySelectedItem
,因为它TabControl
使用对象,而不是TabItem
。
和两个 ViewModel: MainViewModel.cs
public class MainViewModel
{
public MainViewModel()
{
this.Items = new ObservableCollection<TabItemViewModel>
{
new TabItemViewModel("Tab 1", OnItemRequestClose),
new TabItemViewModel("Tab item 2", OnItemRequestClose)
};
}
public ObservableCollection<TabItemViewModel> Items { get; set; }
public void OnItemRequestClose(TabItemViewModel item)
{
this.Items.Remove(item);
}
}
TabItemViewModel.cs
public class TabItemViewModel
{
public TabItemViewModel(string title, Action<TabItemViewModel> onClose)
{
this.Title = title;
this.RequestCloseCommand = new DelegateCommand(_ => onClose(this));
//Just a demontration
this.Content = "Test content "+title;
}
public string Title { get; set; }
public ICommand RequestCloseCommand { get; set; }
public object Content { get; set; }
}
您可以模板 TabItem 具有某种关闭按钮,您可以在后面的代码中连接以关闭当前选定的选项卡。
<Style TargetType="TabItem">
<Setter.Value>
<ControlTemplate TargetType="sdk:TabItem">
<Button x:Name="PART_btnClose"
Height="15"
Width="15"
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="20,0,3,8" BorderThickness="1" Cursor="Hand" />
</ControlTemplate>
</Setter.Value>
</Style>
在此之后,在应用模板中,您可以订阅 ButtonClicked 事件。
像这样的东西:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
PART_btnClose = GetTemplateChild("PART_btnClose") as Button;
if (PART_btnClose != null)
{
PART_btnClose.Click += new RoutedEventHandler(PART_btnClose_Click);
}
在这种情况下,您可以关闭您的标签。
希望这会有所帮助,代码可能无法按原样工作,只是快速完成。
泰罗扎克