Home > front end >  WPF: How to hide specific tab item in TabControl that with DataTemplate bind to views
WPF: How to hide specific tab item in TabControl that with DataTemplate bind to views

Time:09-12

I have a WPF xaml TabControl defined as below, how to set Visibility to Collapsed for the tab item based on binding? Current code:

<TabControl>
    <DataTemplate DataType="{x:Type foo:FooViewModel}">
        <foo:FooView/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type bar:BarViewModel}">
        <bar:BarView/>
    </DataTemplate>
<TabControl/>

What I want to implement to only hide foo TabItem based on condition, but seems it cannot specify the target name?? E.g. hide the template which name is Foo. Thanks for your help, have a nice day.

<TabControl ItemsSource="{Binding ParentModel}">
    <DataTemplate x:Name="Foo" DataType="{x:Type foo:FooViewModel}">
        <foo:FooView/>
    </DataTemplate>
    <DataTemplate x:Name="Bar" DataType="{x:Type bar:BarViewModel}">
        <bar:BarView/>
    </DataTemplate>

    <TabControl.ItemContinerStyle>
        <Style TargetType="TabItem" 'e.g. TargetName="Foo"<==========='>
        <Style.Triggers>
             ...Some trigger condition ignored here
             <Setter Property="Visibility" Value="Collapsed" />
        </Style.Triggers>
        </Style>
    <TabControl.ItemContinerStyle/>
<TabControl/>

CodePudding user response:

Hiding the TabItem element is visually equivalent to removing the element. Since you use data templating, the usual procedure would be to filter the source collection based on your condition to remove the data model. Removing the data model will result in the corresponding container (defined by the DataTemplate) not being rendered i.e. it will be hidden.
In WPF you always focus on the data models and not on their containers. It makes thinks a lot easier.

In the view model that defines the ParentModel property, you can define the filter by accessing the ICollectionView of the source collection:

private void ApplyFilter()
{
  ICollectionView parentModelView = CollectionViewSource.GetDefaultView(this.ParentModel);

  // Remove all items from the view that satisfy the condition
  parentModelView.Filter = Predicate;
}

private bool Predicate(object collectionItem)
{
  // TODO::Implement condition: return 'true' to hide the item from the view
}

If you want to filter the view directly (not recommended) you can access the ItemsControl.Items property to obtain the current ICollectionView:

private void OnMainWIndowLoaded(object sender, EventArgs e)
{
  this.TabControl.Items.Filter = Predicate;
}

private bool Predicate(object collectionItem)
{
  // TODO::Implement condition: return 'true' to hide the item from the view
}

CodePudding user response:

Can't you simply control it on the element?

<TabControl>
    <TabItem Header="Tabitem 1" Visibility="{Binding TabItem1Visibility, Converter={StaticResource BoolToVisibilityConverter}}"/>
    <TabItem Header="Tabitem 2" />
    <TabItem Header="Tabitem 3" />
</TabControl>

where TabItem1Visibility is a property in your VM:

private bool _tabItem1Visibility;

public bool TabItem1Visibility
{
    get { return _tabItem1Visibility; }
    set 
    { 
        _tabItem1Visibility = value; 
        OnPropertyChanged(); 
    }
}

Notes:

  1. BoolToVisibilityConverter's Convert method must return Collapse in case the value is false, not Hidden.
  2. If you set TabItem1Visibility to false while the tab is selected, the content will still shown up, so you have to add SelectedItem="{Binding SelectedTab, Mode=TwoWay}" to TabControl and update it properly.
  •  Tags:  
  • wpf
  • Related