如何使用 MVVM 将 WPF TabItem 绑定到特定的 C# 类?

问题描述 投票:0回答:1

我想将 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 实现,但我不明白如何实现。

c# wpf mvvm tabcontrol tabitem
1个回答
0
投票

以下基本示例展示了如何设计与相同的数据模型一起使用

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>
© www.soinside.com 2019 - 2024. All rights reserved.