views:

2115

answers:

4

Heya

I have a tab control bound to an observablecollection for dynamic tabs as follows:

<TabControl ItemsSource="{Binding AllTabs}" SelectedIndex="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                   <!--.............. -->
            </DataTemplate>
        </TabControl.ItemTemplate>

        <TabControl.ContentTemplate>
            <DataTemplate DataType="{x:Type vm:TabViewModel}">
                <c:MyTabItem/>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>

So, the tab headers and contents are defined dynamically and assigned as the observable collection changes. Now, I would like to hide some tabs without deleting them in the collection behind - in order to keep the data should the tab reopen.

Ideally, each chat tab viewmodel has a IsVisible property that is set to true by default. However, where do I bind such a property to in order to make a tab item collapse?

+1  A: 

I suggest using a CollectionView. This is kind of like an abstract view of a collection where you can see a filtered portion of it. By binding to the CollectionView rather than the collection itself, you should be able to only see the ones you want, and the collection is still there in the background.

Scott Whitlock
+4  A: 

If you can modify your vm:TabViewModel I should change your IsVisible to a Visibility property and use the following ContentTemplate:

<TabControl.ContentTemplate>
    <DataTemplate DataType="{x:Type vm:TabViewModel}">
     <c:MyTabItem Visibility={Binding Visibility}/>
    </DataTemplate>
</TabControl.ContentTemplate>

Else you could use a converter to change the boolean IsVisible to an Visibility enum:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows;

namespace Something.Converters
{
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class BoolToVisibilityConverter : IValueConverter
    {

     #region IValueConverter Members
     /// <summary>
     /// Converts a value.
     /// </summary>
     /// <param name="value">The value produced by the binding source.</param>
     /// <param name="targetType">The type of the binding target property.</param>
     /// <param name="parameter">The converter parameter to use.</param>
     /// <param name="culture">The culture to use in the converter.</param>
     /// <returns>
     /// A converted value. If the method returns null, the valid null value is used.
     /// </returns>
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
      if (value is bool && targetType == typeof(Visibility))
      {
       bool val = (bool)value;
       if (val)
        return Visibility.Visible;
       else
        if (parameter != null && parameter is Visibility )
         return parameter;
        else
         return Visibility.Collapsed;
      }
      throw new ArgumentException("Invalid argument/return type. Expected argument: bool and return type: Visibility");
     }

     /// <summary>
     /// Converts a value.
     /// </summary>
     /// <param name="value">The value that is produced by the binding target.</param>
     /// <param name="targetType">The type to convert to.</param>
     /// <param name="parameter">The converter parameter to use.</param>
     /// <param name="culture">The culture to use in the converter.</param>
     /// <returns>
     /// A converted value. If the method returns null, the valid null value is used.
     /// </returns>
     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
      if (value is Visibility && targetType == typeof(bool))
      {
       Visibility val = (Visibility)value;
       if (val == Visibility.Visible)
        return true;
       else
        return false;
      }
      throw new ArgumentException("Invalid argument/return type. Expected argument: Visibility and return type: bool");
     }
     #endregion
    }
}

Inculde the namespace in your xaml (your root element, Window in this example):

<Window xmlns:converters="clr-namespace:Something.Converters"
.../>

And in your resources:

<Window.Resources>
    <converters:BoolToVisibilityConverter x:Key="boolToVisibilityConverter"/>
</Window.Resources>

And finaly the binding:

<TabControl.ContentTemplate>
    <DataTemplate DataType="{x:Type vm:TabViewModel}">
     <c:MyTabItem Visibility={Binding IsVisible, Converter={StaticResource boolToVisibilityConverter}, ConverterParameter=Visibility.Collapsed}/>
    </DataTemplate>
</TabControl.ContentTemplate>

I think thats it :)

Edit: Ow and change the ConverterParameter to Visibility.Collapsed to Visibility.Hidden for hidden ;)

Zenuka
worked perfectly! thanks :)
bluebit
A: 

I tried but did not get the expected results. The following approach of binding Visibility in the TabControl.ContentTemplate results in hiding the content of the tab and not the tab header itself.

<TabControl.ContentTemplate> <DataTemplate DataType="{x:Type vm:TabViewModel}"> <c:MyTabItem Visibility={Binding Visibility}/> </DataTemplate> </TabControl.ContentTemplate>

Still fighting out to hide the tab header itself.

Jolly
+1  A: 

Got the correct answer with the help of this answer

<TabControl.ItemContainerStyle>
  <Style TargetType="{x:Type TabItem}">
    <Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource boolToVisibilityConverter}"/>
  </Style>
</TabControl.ItemContainerStyle>

Use the System.Windows.Controls.BooleanToVisibilityConverter for conversion from bool to Visibilty.

Scott's suggestion of using CollectionView is also promising.

Jolly