Wpf 如何创建TabControl(自定义控件)的可关闭TabItem?
我的英语水平很差,因为我不是以英语为母语的人。 我希望你能理解 我想创建具有可关闭功能的选项卡控件。(ClosableTabControl) ClosableTabControl必须具有在单击关闭按钮时关闭选项卡项的功能。 另外,我想自动删除与关闭的选项卡项相关的ItemsSource 因此,我希望在外部项目中使用ClosableTabControl,如下所示Wpf 如何创建TabControl(自定义控件)的可关闭TabItem?,wpf,binding,tabcontrol,Wpf,Binding,Tabcontrol,我的英语水平很差,因为我不是以英语为母语的人。 我希望你能理解 我想创建具有可关闭功能的选项卡控件。(ClosableTabControl) ClosableTabControl必须具有在单击关闭按钮时关闭选项卡项的功能。 另外,我想自动删除与关闭的选项卡项相关的ItemsSource 因此,我希望在外部项目中使用ClosableTabControl,如下所示 class MainViewModel { public ObservableCollection<DocumentVie
class MainViewModel
{
public ObservableCollection<DocumentViewModel> Documents {get;}
...
}
class DocumentViewModel
{
public string Title {get;}
public object Content {get;}
}
<Window DataContext="MainViewModel">
<ClosableTabControl ItemsSource="Documents"
HeaderBinding="{Binding Title}"/>
</Window>
class主视图模型
{
公共可观察收集文档{get;}
...
}
类DocumentViewModel
{
公共字符串标题{get;}
公共对象内容{get;}
}
如您所见,无需连接close命令即可删除外部项目中的文档。
此外,它不需要将ItemTemplate重写为绑定。(使用HeaderBinding功能可以解决此问题)
我认为上面的自定义控件为外部项目提供了方便
我试图创建上面的控件,但我遇到了下面的问题
1。它无法删除ClosableTabControl的ItemsSource元素。(关闭选项卡项时需要此选项)
2。我不知道如何实现HeaderBinding功能。
我应该做什么来解决上述问题?
我希望你能帮助我
感谢阅读。这个简单快速的示例扩展了
TabControl
,并覆盖了TabControl
的默认样式。新的样式
必须放在“/Themes/Generic.xaml”文件中。样式
覆盖默认的选项卡项
控制模板
,并向其添加关闭按钮
按钮.命令
绑定到ClosableTabControl
的路由命令CloseTabRoutedCommand
调用后,ClosableTabControl
检查项
集合是否通过数据绑定或例如XAML填充
如果通过ItemsSource
(绑定)创建了TabItem
,则将执行ICommand
属性ClosableTabControl.removietem命令
,以便视图模型从集合中删除该项。这是为了避免直接从ItemsSource
中删除项,这将破坏此属性上的绑定。传递给命令委托的参数是选项卡项的数据模型(在您的类型为DocumentViewModel
)被请求删除。
如果选项卡项
是通过XAML创建的,则该项将直接删除,而不需要视图模型中的命令
MainViewModel.cs
class MainViewModel
{
public ObservableCollection<DocumentViewModel> Documents {get;}
// The remove command which is bound to the ClosableTabControl RemoveItemCommand property.
// In case the TabControl.ItemsSource is data bound,
// this command will be invoked to remove the tab item
public ICommand RemoveTabItemCommand => new AsyncRelayCommand<DocumentViewModel>(item => this.Documents.Remove(item));
...
}
public class ClosableTabControl : TabControl
{
public static readonly RoutedUICommand CloseTabRoutedCommand = new RoutedUICommand(
"Close TabItem and remove item from ItemsSource",
nameof(ClosableTabControl.CloseTabRoutedCommand),
typeof(ClosableTabControl));
// Bind this property to a ICommand implementation of the view model
public static readonly DependencyProperty RemoveItemCommandProperty = DependencyProperty.Register(
"RemoveItemCommand",
typeof(ICommand),
typeof(ClosableTabControl),
new PropertyMetadata(default(ICommand)));
public ICommand RemoveItemCommand
{
get => (ICommand) GetValue(ClosableTabControl.RemoveItemCommandProperty);
set => SetValue(ClosableTabControl.RemoveItemCommandProperty, value);
}
static ClosableTabControl()
{
// Override the default style.
// The new Style must be located in the "/Themes/Generic.xaml" ResourceDictionary
DefaultStyleKeyProperty.OverrideMetadata(typeof(ClosableTabControl), new FrameworkPropertyMetadata(typeof(ClosableTabControl)));
}
public ClosableTabControl()
{
this.CommandBindings.Add(
new CommandBinding(ClosableTabControl.CloseTabRoutedCommand, ExecuteRemoveTab, CanExecuteRemoveTab));
}
private void CanExecuteRemoveTab(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.OriginalSource is FrameworkElement frameworkElement
&& this.Items.Contains(frameworkElement.DataContext)
|| this.Items.Contains(e.Source);
}
private void ExecuteRemoveTab(object sender, ExecutedRoutedEventArgs e)
{
if (this.ItemsSource == null)
{
object tabItemToRemove = e.Source;
this.Items.Remove(tabItemToRemove);
}
else
{
object tabItemToRemove = (e.OriginalSource as FrameworkElement).DataContext;
if (this.RemoveItemCommand?.CanExecute(tabItemToRemove) ?? false)
{
this.RemoveItemCommand.Execute(tabItemToRemove);
}
}
}
}
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type ClosableTabControl}"
BasedOn="{StaticResource {x:Type TabControl}}">
<Setter Property="Background"
Value="{x:Static SystemColors.ControlBrush}" />
<!-- Add a close button to the tab header -->
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
<Setter Property="BorderThickness"
Value="1,1,1,0" />
<Setter Property="Margin"
Value="0,2,0,0" />
<Setter Property="BorderBrush" Value="DimGray" />
<Setter Property="Background" Value="LightGray" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<StackPanel Orientation="Horizontal">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True" />
<Button Content="X"
Command="{x:Static local:ClosableTabControl.CloseTabRoutedCommand}"
Height="16"
Width="16"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Margin="4" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background"
Value="{x:Static SystemColors.ControlBrush}" />
<Setter Property="Panel.ZIndex"
Value="100" />
<Setter Property="Margin"
Value="0,0,0,-1" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<!-- Provide a default DataTemplate for the tab header
This will only work if the data item has a property Title -->
<Setter Property="ItemTemplate">
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</Setter.Value>
</Setter>
<!-- Provide a default DataTemplate for the tab content
This will only work if the data item has a property Content -->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{Binding Content}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
用法示例
<Window>
<Window.DataContext>
<MainViewModel" x:Name="MainViewModel" />
</Window.DataContext>
<ClosableTabControl ItemsSource="{Binding Documents}"
RemoveItemCommand="{Binding RemoveTabItemCommand}" />
</Window>
<Window>
<Window.DataContext>
<MainViewModel" x:Name="MainViewModel" />
</Window.DataContext>
<ClosableTabControl ItemsSource="{Binding Documents}" />
</Window>
这回答了你的问题吗?您需要显示实现,否则没有人知道为什么删除项不起作用。另外,不要从ItemsSource
中删除项目,而是将选项卡item.Visibility
设置为Visibility.Collapsed
。控件不应该弄乱数据。它也更容易实现“重新打开最近关闭的”行为。哦,这是个好主意。我会考虑的。
<Window>
<Window.DataContext>
<MainViewModel" x:Name="MainViewModel" />
</Window.DataContext>
<ClosableTabControl ItemsSource="{Binding Documents}" />
</Window>