2

I'm struggling with relative Sources. I'm inside Tab Items and I want to reach the parent ModelView. The goal is to make some context menu items invisble, if the item is the last tab.

ViewModel:

public bool IsLastTab => ItemCollection.Count > 1;

xaml:

<Window x:Name="MainWinodw"
    ...
    xmlns:ct="clr-namespace:ChromeTabs;assembly=ChromeTabs"
    xmlns:vm="clr-namespace:Main.ViewModel"
    xmlns:conv="clr-namespace:Main.Converters"
    xmlns:ctConv="clr-namespace:ChromeTabs.Converters;assembly=ChromeTabs"
    xmlns:usercontrols="clr-namespace:Main.UserControls"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    ...
    DataContext="{Binding Source={StaticResource Locator},Path=Main}" ">
<Window.Resources>
    <conv:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
    ...
</Window.Resources >
<Grid>
    <ct:ChromeTabControl x:Name="MyChromeTabControl"
                         TabPersistBehavior="Timed"
                         TabPersistDuration="0:0:0:5"
                         AddTabButtonBehavior="OpenNewTab"
                         Background="AliceBlue"
                         ItemsSource="{Binding ItemCollection}"
                          ...">
        ...
        <ct:ChromeTabControl.ItemTemplate>
            <DataTemplate>
                <Grid Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type ct:ChromeTabItem}}}">
                    ...
                    <Grid.ContextMenu>
                        <ContextMenu>
                            <MenuItem Header="Close"
                                      Command="{Binding Path=PlacementTarget.Tag.CloseTabCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                                      Visibility="{Binding IsLastTab,  
                                                    RelativeSource={RelativeSource AncestorType={x:Type vm:ViewModelChromeTabs}}, 
                                                    Mode=OneWay, 
                                                    Converter={StaticResource InverseBooleanToVisibilityConverter}}"
                                      CommandTarget="{Binding Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
                            ...
                            <Separator />
                            <MenuItem Header="{Binding IsPinned, Converter={StaticResource BooleanToPinTabTextConverter}}"
                                      Command="{Binding Path=PlacementTarget.Tag.PinTabCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                                      CommandTarget="{Binding Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                                      CommandParameter="{Binding}" />
                        </ContextMenu>
                    </Grid.ContextMenu>
                </Grid>
            </DataTemplate>
        </ct:ChromeTabControl.ItemTemplate>
    </ct:ChromeTabControl>
</Grid>
</Window>

It's working when I put it in the Item Class but there I have no Info about how many Tabs are left, and it seems counter logic to implement a messenger here for this.

Cœur
  • 37,241
  • 25
  • 195
  • 267
k4yaman
  • 475
  • 8
  • 20
  • 2
    Your ViewModel is probably not in the LogicalTree. You should bind to the datacontext of your window instead: `{Binding DataContext.IsLastTab, RelativeSource={RelativeSource AncestorType={x:Type Window}}` – Freggar Jun 18 '18 at 10:57
  • Hellor Freggar, didn't help. The Viewmodel works with `ItemsSource="{Binding ItemCollection}"` but after the tag its only applying the items model – k4yaman Jun 18 '18 at 11:01
  • Then it's time to create a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). Because I have no clue other than that why the binding does not work. You could also look at the debug console for any Binding Expression errors. – Freggar Jun 18 '18 at 11:11
  • 1
    Oh I'm stupid. `RelativeSource` won't work since a `ContextMenu` does not share the same VisualTree. See https://stackoverflow.com/questions/3583507/wpf-binding-a-contextmenu-to-an-mvvm-command for more info – Freggar Jun 18 '18 at 11:17
  • Thanks, thats exactly my question. Didn't find this one before. I'll try this one – k4yaman Jun 18 '18 at 11:28

1 Answers1

2

You have defined IsLastTab like this:

public bool IsLastTab => ItemCollection.Count > 1;

This does not seem to determine whether the current tab is the last one.

You need something like that:

public bool IsLastTab => ReferenceEquals(this, ItemCollection.LastOrDefault());

(Since you did not post the underlying view models, this is just a guess. The exact code might change.)

And you also need to call INotifyPropertyChanged.PropertyChanged for the property "IsLastTab" for each tab item whenever the tab collection changes.

FrankM
  • 1,007
  • 6
  • 15
  • Well it doesn't reach the getter anyway yet. I could probably notify the last item in the list with the PropertyChanged Event. Thanks for this, i'll try it but it isn't my desired solution – k4yaman Jun 18 '18 at 11:05