Question

I have the following Style for a TabItem

<Style x:Key="SubStudioTabItem" TargetType="{x:Type TabItem}">
  <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
  <Setter Property="Background" Value="Transparent"/>
  <Setter Property="Template">
     <Setter.Value>
        <ControlTemplate TargetType="{x:Type TabItem}">
           <Grid Height="20" 
                        Background="{TemplateBinding Background}" 
                        SnapsToDevicePixels="True">
              <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="Auto"/>
                 <ColumnDefinition Width="20"/>
              </Grid.ColumnDefinitions>
              <ContentPresenter Grid.Column="0" 
                                Margin="10,0,10,0" 
                                HorizontalAlignment="Center" 
                                VerticalAlignment="Center" 
                                ContentSource="Header" />
              <Button Grid.Column="1" 
                      x:Name="CloseButton" 
                      Width="15" 
                      Height="15" 
                      HorizontalAlignment="Center" 
                      VerticalAlignment="Center" 
                      DockPanel.Dock="Right" 
                      AttachedCommand:CommandBehavior.Event="Click"
                      AttachedCommand:CommandBehavior.Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, 
                                                                        Path=DataContext.CloseWorkspaceCommand}">
              ...

Now I want to make the visibility of the Button on the TabItem optional which can be used in a DataTemplate like

<DataTemplate x:Key="WorkspaceTemplate">
    <TabControl x:Name="tabControl" 
                IsSynchronizedWithCurrentItem="true" 
                Style="{StaticResource StudioTabControl}"
                ItemsSource="{Binding Workspaces}" 
                SelectedIndex="{Binding SelectedIndex, NotifyOnSourceUpdated=True, Mode=TwoWay}">
        <TabControl.ItemContainerStyle>
            <Style TargetType="TabItem" 
                   BasedOn="{StaticResource SubStudioTabItem}">
                <Setter Property="??Button.Visibility??" Value="{Binding Path=Display, Converter={StaticResource BooleanToVisibiltyConverter}}"/>
            </Style>
        </TabControl.ItemContainerStyle>
    </TabControl>
</DataTemplate>

How can I set the state of the visibility of the button on the TabItem from the DataTemplate?

Thanks for your time.

Was it helpful?

Solution

In that case, I would create an attached property, such as type of Visibility and would make a TemplateBinding in the Style, something like this:

<ControlTemplate TargetType="{x:Type TabItem}">
...
    <Button Grid.Column="1" 
                x:Name="CloseButton" 
                Visibility="{TemplateBinding local:MyClass.ButtonVisibility}"
                ...
    </Button>

And for TabItem in <ItemContainerStyle> would write this (or somewhere else):

<Style TargetType="TabItem" BasedOn="{StaticResource SubStudioTabItem}">
    <Setter Property="local:MyClass.ButtonVisibility" Value="{Binding Path=Display, Converter={StaticResource BooleanToVisibiltyConverter}}"/>
</Style>

Edit:

I created a project that implements this method. In the project tried to follow the MVVM pattern. The structure of the project:

enter image description here

Start in order, in folder AttachedProperties there is an attached property, which is responsible for the appearance of the Button.

The code of ButtonVisibility.cs:

using System;
using System.Windows;

public class ButtonVisibilityPro : DependencyObject
{
    public static readonly DependencyProperty ButtonVisibilityProperty;

    public static void SetButtonVisibility(DependencyObject DepObject, Visibility value)
    {
        DepObject.SetValue(ButtonVisibilityProperty, value);
    }

    public static Visibility GetButtonVisibility(DependencyObject DepObject)
    {
        return (Visibility)DepObject.GetValue(ButtonVisibilityProperty);
    }

    static ButtonVisibilityPro()
    {
        PropertyMetadata MyPropertyMetadata = new PropertyMetadata(Visibility.Collapsed);

        ButtonVisibilityProperty = DependencyProperty.RegisterAttached("ButtonVisibility",
                                                            typeof(Visibility),
                                                            typeof(ButtonVisibilityPro),
                                                            MyPropertyMetadata);
    }
}

The data model is ButtonModel, wherein the boolean property is ButtonDisplay. This class inherits from the ViewModelBase, that implements INotifyPropertyChanged.

ButtonModel.cs

using System;
using ButtonVisibilityHelp.ViewModels;

namespace ButtonVisibilityHelp.Models
{
    public class ButtonModel : ViewModelBase
    {
        private bool _buttonDisplay = false;

        public bool ButtonDisplay
        {
            get 
            {
                return _buttonDisplay; 
            }

            set
            {
                _buttonDisplay = value;
                NotifyPropertyChanged("ButtonDisplay");             
            }
        }
    }
}

ViewModelBase.cs

using System;
using System.ComponentModel;

namespace ButtonVisibilityHelp.ViewModels
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

ButtonViewModel.cs

using System;
using System.Windows.Input;
using System.Windows;

using ButtonVisibilityHelp.Models;
using ButtonVisibilityHelp.Workers;

namespace ButtonVisibilityHelp.ViewModels
{
    public class ButtonViewModel : ViewModelBase
    {
        private ButtonModel _buttonModel;

        private ICommand _hideButtonCommand = null;
        private ICommand _showButtonCommand = null;

        public ButtonModel ButtonModel
        {
            get
            {
                return _buttonModel;
            }

            set
            {
                _buttonModel = value;
                NotifyPropertyChanged("ButtonModel");
            }
        }

        public ICommand HideButtonCommand
        {
            get
            {
                if (_hideButtonCommand == null)
                {
                    _hideButtonCommand = new RelayCommand(param => this.HideButton(), null);
                }

                return _hideButtonCommand;
            }
        }

        public ICommand ShowButtonCommand
        {
            get
            {
                if (_showButtonCommand == null)
                {
                    _showButtonCommand = new RelayCommand(param => this.ShowButton(), null);
                }

                return _showButtonCommand;
            }
        }

        public ButtonViewModel()
        {
            ButtonModel = new ButtonModel();
        }

        private void HideButton() 
        {            
            ButtonModel.ButtonDisplay = false;
        }

        private void ShowButton() 
        {
            ButtonModel.ButtonDisplay = true;
        }
    }
}   

RelayCommand.cs

using System;
using System.Windows.Input;

namespace ButtonVisibilityHelp.Workers
{
    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public RelayCommand(Action<object> execute) : this(execute, null)
        {
        }

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
            {
                throw new ArgumentNullException("execute");
            }

            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }

            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

Below is a piece of XAML code that is in the style of TabItem:

<Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <Grid Background="{TemplateBinding Background}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="20"/>
                    </Grid.ColumnDefinitions>

                    <Border Grid.Column="0" SnapsToDevicePixels="True" Name="Border" Margin="0,0,2,0" Padding="2" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="0">
                        <ContentPresenter Name="ContentSite" 
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              Margin="5,5,5,5"
                                              VerticalAlignment="Center" 
                                              RecognizesAccessKey="True" 
                                              ContentSource="Header" />                            
                    </Border>

                    <!-- Here TemplateBinding for Visibility -->
                    <Button Name="CloseButton" Style="{StaticResource CloseButton}" 
                                Visibility="{TemplateBinding AttachedProperties:ButtonVisibilityPro.ButtonVisibility}" 
                                Grid.Column="1" Width="14" Height="14" HorizontalAlignment="Center" />
                </Grid>

                <ControlTemplate.Triggers>
                    <Trigger Property="TabStripPlacement" Value="Bottom">
                        <Setter TargetName="Border" Property="CornerRadius" Value="0,0,0,0" />
                    </Trigger>                            
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
</Setter>   

XAML of MainWindow:

<Window x:Class="ButtonVisibilityHelp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ViewModels="clr-namespace:ButtonVisibilityHelp.ViewModels"
    xmlns:AttachedProperties="clr-namespace:ButtonVisibilityHelp.AttachedProperties"
    WindowStartupLocation="CenterScreen"
    Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <ViewModels:ButtonViewModel x:Key="MyButtonViewModel" />
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </Window.Resources>

    <Grid DataContext="{Binding Source={StaticResource MyButtonViewModel}}">
        <TabControl>
            <TabControl.ItemContainerStyle>
                <Style TargetType="{x:Type TabItem}" BasedOn="{StaticResource {x:Type TabItem}}">
                    <Setter Property="AttachedProperties:ButtonVisibilityPro.ButtonVisibility" Value="{Binding Path=ButtonModel.ButtonDisplay, Converter={StaticResource BooleanToVisibilityConverter}}" />
                </Style>
            </TabControl.ItemContainerStyle>

            <TabItem Header="Test1">
                <StackPanel>
                    <TextBlock Text="{Binding ButtonModel.ButtonDisplay, StringFormat=ButtonDisplay: {0}, Mode=TwoWay}" HorizontalAlignment="Right" />

                    <Button Name="ShowInTest1" Command="{Binding ShowButtonCommand}" Width="100" Height="30" Content="Show me" HorizontalAlignment="Right" />
                    <Button Name="HideInTest1" Command="{Binding HideButtonCommand}" Width="100" Height="30" Content="Hide me" HorizontalAlignment="Right" />                   
                </StackPanel>
            </TabItem>

            <TabItem Header="Test2">
                <StackPanel>
                    <TextBlock Text="{Binding ButtonModel.ButtonDisplay, StringFormat=ButtonDisplay: {0}, Mode=TwoWay}" HorizontalAlignment="Right" />

                    <Button Name="ShowInTest2" Command="{Binding ShowButtonCommand}" Width="100" Height="30" Content="Show me" HorizontalAlignment="Right" />
                    <Button Name="HideInTest2" Command="{Binding HideButtonCommand}" Width="100" Height="30" Content="Hide me" HorizontalAlignment="Right" />
                </StackPanel>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

Output

Show me:

enter image description here

Hide me:

enter image description here

The complete code example is available at this link.

OTHER TIPS

Set the Tag property on your TabItem in style like below :

<TabControl.ItemContainerStyle>
        <Style TargetType="TabItem" 
               BasedOn="{StaticResource SubStudioTabItem}">
            <Setter Property="Tag" Value="{Binding IsVisible, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
        </Style>
    </TabControl.ItemContainerStyle>

And then in ControlTemplate add DataTrigger to set the Visibility of CloseButton depending on Tag property

<ControlTemplate.Triggers>
   <DataTrigger Binding="{Binding Tag}", Value="false">
     <Setter Property="Visibility" TargetName="CloseButton" Value="Collapsed"/>
     </DataTrigger>
</ControlTemplate.Triggers>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top