OwenP
OwenP

Reputation: 25408

How do I bind a close button in a TabControl header to a command in the window's ViewModel?

I'm working on a tool and want to add a close button to the tabs in a TabControl. I can't figure out how to make the Command property of the button bind to the appropriate property on my window's ViewModel.

The VM is straightforward. Just INPC implementation and an ICommand property named CloseSelectedFileCommand.

The TabControl's XAML with other parts omitted, nothing pretty because pretty is for after "it works":

<TabControl ItemsSource="{Binding Results}" 
            SelectedItem="{Binding SelectedFile}">
    <TabControl.ItemTemplate>
        <!-- Type is ResultInfo -->
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding FileName}" />
                <Button Grid.Column="1" Command="{Binding Path=CloseSelectedFileCommand}">X</Button>
            </Grid>
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate>
          ...
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

I get what's happening. From the perspective of the button, the current item is one of the items from my collection. They don't have a DataContext and if they did it certainly wouldn't be my Window's ViewModel. I can't figure out how to make this work. I thought perhaps a RelativeSource looking for a Window ancestor would help, but it didn't.

I've looked at a few Google searches. They seem to suggest that my data item should itself be a ViewModel and have this command on it. That's... kind of odd since the collection of items belongs to the Window. Similar StackOverflow posts seem to suggest making the bound items ViewModels themselves and giving them a command that raises an event that's handled by the window. I don't understand what extra layers of indirection on top of "the button raises an event when clicked" do for me. I guess it's the only way? I can't think of a way to shuttle the DataContext of the Window to this XAML.

Upvotes: 1

Views: 1365

Answers (1)

NSGaga
NSGaga

Reputation: 14312

Maybe this could work for you, all along those lines...
Bind Button's data context (or anywhere else you might need)...

DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext}"  

This providing you have a window somewhere 'above' it.

Or if you have specific Name you can use ElementName similarly to RelativeSource.

Hope this helps

Upvotes: 1

Related Questions