UWP Databinding: How to set button command to parent DataContext inside DataTemplate

RAB picture RAB · Jan 23, 2016 · Viewed 8.2k times · Source

Short explanation of need: I need to fire the command of a button inside a DataTemplate, using a method from the DataContext of the ViewModel.

Short explanation of problem: The templated button command only seems to be bindable to the datacontext of the item itself. The syntax used by WPF and Windows 8.1 apps to walk up the visual tree doesn't seem to work, including ElementName and Ancestor binding. I would very much prefer not to have my button command located inside the MODEL.

Side Note: This is built with the MVVM design method.

The below code generates the list of items on the VIEW. That list is one button for each list item.

            <ItemsControl x:Name="listView" Tag="listOfStories" Grid.Row="0" Grid.Column="1"
            ItemsSource="{x:Bind ViewModel.ListOfStories}"
            ItemTemplate="{StaticResource storyTemplate}"
            Background="Transparent"
            IsRightTapEnabled="False"
            IsHoldingEnabled="False"
            IsDoubleTapEnabled="False"
                 />

Inside the page resources of the same VIEW, I have created a DataTemplate, containing the problematic button in question. I went ahead and stripped out most of the formatting inside the button, such as text, to make the code easier to read on this side. Everything concerning the button works, except for the problem listed, which is the binding of the command.

<Page.Resources>
        <DataTemplate x:Name="storyTemplate" x:DataType="m:Story">
            <Button
                Margin="0,6,0,0"
                Width="{Binding ColumnDefinitions[1].ActualWidth, ElementName=storyGrid, Mode=OneWay}"
                HorizontalContentAlignment="Stretch"
                CommandParameter="{Binding DataContext, ElementName=Page}"
                Command="{Binding Source={StaticResource Locator}}">

                <StackPanel HorizontalAlignment="Stretch" >
                    <TextBlock Text="{x:Bind StoryTitle, Mode=OneWay}"
                        FontSize="30"
                        TextTrimming="WordEllipsis"
                        TextAlignment="Left"/>
                </StackPanel>
            </Button>
        </DataTemplate>
    </Page.Resources>

Because this is a DataTemplate, the DataContext has been set to the individual items that comprise the list (MODEL). What I need to do is select the DataContext of the list itself (VIEWMODEL), so I can then access a navigation command.

If you are interested in the code-behind of the VIEW page, please see below.

    public sealed partial class ChooseStoryToPlay_View : Page
    {
    public ChooseStoryToPlay_View()
    {
        this.InitializeComponent();
        this.DataContextChanged += (s, e) => { ViewModel = DataContext as ChooseStoryToPlay_ViewModel; };
    }
    public ChooseStoryToPlay_ViewModel ViewModel { get; set; }
}

I've tried setting it by ElementName, among many other attempts, but all have failed. Intellisense detects "storyTemplate" as an option when ElementName is input, which is the name of the DataTemplate shown in the first code block of this question.

I don't believe my problem can be unique, however I'm having great difficulty finding a solution for UWP. Allow me to apologize in advance in this is a simple question, but I've spent nearly two days researching answers, with none seeming to work for UWP.

Thank you guys!

Answer

Andrei Ashikhmin picture Andrei Ashikhmin · Jan 24, 2016

What MVVM toolkit are you using (if any)? In MVVM Light, you can get a hold of ViewModel from DataTemplate same way you set DataContext for your view:

<DataTemplate x:Key="SomeTemplate">
    <Button Command="{Binding Main.MyCommand, Source={StaticResource ViewModelLocator}}"/>
</DataTemplate>