我想将 TabControl 的每个 TabItem 绑定到特定的 C# 类,以使用类属性的状态来对 View 进行反应。我尝试使用 MVVM,我知道为了更好地将对象集合绑定到 TabControl 的 ItemsSource,但在我的例子中,我想要绑定的类非常不同,并且只有少数属性必须相同。我没有使用集合,因为客户希望按组查看选项卡项目,我必须更改 TabControl 的标准样式,并且必须在 XAML 中创建每个项目并绑定到特定元素
<TabControl>
<TabControl.Resources>
<Style x:Key="TabItemDefaultStyle" TargetType="TabItem">
<Setter Property="Height" Value="{StaticResource SquareButtonSize}"/>
<Setter Property="Width" Value="{StaticResource SquareButtonSize}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<ControlTemplate.Resources>
<Storyboard x:Key="TabItemBorderBackgroundBlinking" >
<ColorAnimation Storyboard.TargetName="TabItemBorder" Storyboard.TargetProperty="Background.Color" From="LightBlue" To="Red" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="Forever" />
</Storyboard>
</ControlTemplate.Resources>
<Border Name="TabItemBorder" BorderThickness="1" BorderBrush="Black" CornerRadius="5" Margin="1">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="5"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="TabItemBorder" Property="Background" Value="{StaticResource GeneralColor}" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="TabItemBorder" Property="Background" Value="Transparent" />
</Trigger>
<DataTrigger Binding="{Binding IsAlarm}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="BeginTabItemBorderBackgroundBlinking" Storyboard="{StaticResource TabItemBorderBackgroundBlinking}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="BeginTabItemBorderBackgroundBlinking"/>
</DataTrigger.ExitActions>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabControl.Template>
<ControlTemplate TargetType="TabControl">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="{StaticResource SettingsPanelWidth}"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Margin="5" Padding="5" BorderBrush="Black" BorderThickness="1,1,1,1" CornerRadius="5">
<Grid IsItemsHost="True" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
</Grid>
</Border>
<ContentPresenter Grid.Column="1" ContentSource="SelectedContent" />
</Grid>
</ControlTemplate>
</TabControl.Template>
<TabItem Grid.Row="0" Style="{StaticResource TabItemDefaultStyle}">
<vc:MainIndicators />
</TabItem>
<TabItem Grid.Row="1" Style="{StaticResource TabItemDefaultStyle}">
<vc:Dueses />
</TabItem>
<TabItem Grid.Row="3" Style="{StaticResource TabItemDefaultStyle}">
<vc:ChartSettings />
</TabItem>
<TabItem Grid.Row="4" Style="{StaticResource TabItemDefaultStyle}">
<vc:GeneralSettings />
</TabItem>
</TabControl>
但是我想将每个 TabItem 绑定到继承基类的对象,以使用其 IsAlarm 属性(您可以在上面的 DataTrigger 标记中的代码中看到它),以便在 IsAlarm=true 时使项目闪烁。看起来我可以通过 DataContext 实现,但我不明白如何实现。
以下基本示例展示了如何设计与相同的数据模型一起使用
TabControl
。
TabControl.ItemsContainerStyle
用于定义数据模型上的属性,该属性应用于呈现选项卡内容 (TabItem.Content
)。
TabControl.ItemTemplate
允许您定义选项卡标题的外观。
TabControl.ContentTemplate
允许您定义当前选定选项卡的布局。我建议为每个内容对象类型定义一个隐式 DataTemplate
。此示例定义了 FirstTabContentDataItem
类型的单个内容对象来给出示例。
TabDataItem.cs
每个选项卡项目都有一个标题、一个图标和它将呈现的数据(内容)。
class TabDataItem : INotifyPropertyChanged
{
public TabDataItem(TabContentModel tabContentModel)
=> this.TabContentModel = tabContentModel;
public TabContentDataItem ContentDataItem { get; }
public string Title { get; set; }
public string IconPath { get; set; }
}
TabContentDataItem.cs
内容数据的基类。
class TabContentDataItem : INotifyPropertyChanged
{
public string Title { get; set; }
}
FirstTabContentDataItem.cs
class FirstTabContentDataItem : TabContentDataItem, INotifyPropertyChanged
{
public string SomeContentTextValue { get; set; }
}
SecondTabContentDataItem.cs
class SecondTabContentDataItem : TabContentDataItem, INotifyPropertyChanged
{
public int SomeContentNumericValue { get; set; }
}
MainViewModel.cs
class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<TabDataItem> TabDataItems { get; }
public MainViewModel()
{
this.TabDataItems = new ObservableCollection<TabDataItem>();
var tabContent = new FirstTabContentDataItem()
{
Title = "MainIndicators",
SomeContentTextValue = "Abc"
};
var tabHeader = new TabDataItem(tabContent)
{
Title = "First tab",
IconPath = "SomeImage.pmg"
};
this.TabDataItems.Add(tabHeader);
tabContent = new SecondTabContentDataItem()
{
Title = "Numbers",
SomeContentNumericValue = 123
};
tabHeader = new TabDataItem(tabContent)
{
Title = "Second tab",
IconPath = "SomeImage.pmg"
};
this.TabDataItems.Add(tabHeader);
}
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
MainWindow.xaml
<Window>
<Window.Resources>
<!--
Define a DataTemplate for the TabControl.ContentTemplate for each
content data type e.g. FirstTabContentDataItem.
Because the DataTemplate is implicit (keyless)
it will be automatically implied
-->
<DataTemplate DataType="FirstTabContentDataItem">
<StackPanel Background="Yellow">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding SomeContentTextValue}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="SecondTabContentDataItem">
<StackPanel Background="Red">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding SomeContentNumericValue}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<TabControl ItemsSource="{Binding TabDataItems}">
<!-- ItemContainerStyle to bind the content data object of the TabDataItem to the TabItem.Content property -->
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Content"
Value="{Binding ContentDataItem}" />
</Style>
</TabControl.ItemContainerStyle>
<!-- ItemTemplate defines how the tab headers look like -->
<TabControl.ItemTemplate>
<DataTemplate DataType="local:TabDataItem">
<Image Source="{Binding IconPath}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl>
</Window>