简体   繁体   中英

Xaml Tag binding fails in button flyout for windows 8.1 store app

I have a windows 8.1 store app and I can't figure out how to get the datacontext to access my viewmodel for a relaycommand. The xaml works all the way up to the flyout and then it fails. So the button with content "buttonWorks" successfully gets the binding from the rootGrid element and calls the command on the viewmodel. But the button right below in the flyout does not. Why?

To make an example of the binding problem, create a new Store App with the Split App template. Then add a flyout to the SplitPage and bind a textbox text to the itemtitle element. The binding will not populate the flyout textbox. The code snippet looks like this:

<Image Source="{Binding ImagePath}" Grid.Row="1" Margin="0,0,20,0" Width="180" Height="180" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
    <StackPanel x:Name="itemDetailTitlePanel" Grid.Row="1" Grid.Column="1">
        <TextBlock x:Name="itemTitle" Margin="0,-10,0,0" Text="{Binding Title}" Style="{StaticResource SubheaderTextBlockStyle}"/>
        <TextBlock x:Name="itemSubtitle" Margin="0,0,0,20" Text="{Binding Subtitle}" Style="{StaticResource SubtitleTextBlockStyle}"/>
            <Button Content="Update">
                <Button.Flyout>
                    <Flyout>
                        <StackPanel>
                            <StackPanel Margin="5" Orientation="Vertical"  >
                                <TextBlock  Text="Item Title" VerticalAlignment="Bottom"/>
                                <TextBox Text="{Binding ElementName=itemTitle,Path=Text,Mode=TwoWay}"  Width="200" />
                            </StackPanel>
                       </StackPanel>
                   </Flyout>
              </Button.Flyout>
          </Button>
       </StackPanel>

I can get the command binding to work using Dani's answer and setting the datacontext on the button hosting the flyout like this, but I can't bind the textboxes as seen in the template example above

<Button Content="Update" HorizontalAlignment="Center" DataContext="{Binding ViewModel, ElementName=pageRoot}" >
<Button.Flyout>
    <Flyout>
        <StackPanel>
            <TextBlock  Text="Item Title" VerticalAlignment="Bottom"/>
            <TextBox Text="{Binding ElementName=itemTitle,Path=Text,Mode=TwoWay}"  Width="200" />

            <Button x:Name="buttonTest" Margin="5" Height="40" Content="Test" HorizontalAlignment="Center"   Command="{Binding UpdateMatchDataCommand}"/>

Original Code Example Problem:

<Grid Name="rootGrid" Tag="{Binding}"  Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

....

   <ScrollViewer
        x:Name="itemDetail"
        AutomationProperties.AutomationId="ItemDetailScrollViewer"
        Grid.Row="0"
        Grid.Column="1"
        Grid.RowSpan="2"
        Padding="60,0,66,0"
        HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"
        DataContext="{Binding SelectedItem, ElementName=itemListView}"

       <Grid x:Name="itemDetailGrid" Margin="0,60,0,50">
           <StackPanel Orientation="Vertical" Grid.Row="1"  Margin="0,0,10,0" Width="180" Height="180">
                <Button Name="buttonWorks" Content="Test" Command="{Binding Tag.UpdateMatchDataCommand,ElementName=rootGrid}"/>

              <Button Content="Update" HorizontalAlignment="Center" >
                  <Button.Flyout>
                      <Flyout>
                          <Button Name="buttonFail" Content="Test" Command="{Binding Tag.UpdateMatchDataCommand,ElementName=rootGrid}"/>
                      </Flyout>
                  </Button.Flyout>
              </Button>
          </StackPanel>


....

If you work with ViewModels I would suggest that you change the DataContext to your page.

<Page
    x:Name="rootPage"
    DataContext="{Binding ViewModel, RelativeSource={RelativeSource Self}}"
...

And CodeBehind:

private readonly ViewModel _viewModel = new ViewModel();
public ViewModel ViewModel
{
    get { return _viewModel; }
}

Now you can change your commands to:

<Button Name="buttonWorks" Content="Test" Command="{Binding Tag.UpdateMatchDataCommand}"/>

ElementName is now only necessary if you bind to a property in code behind.

It ends up that I could never solve the problem using the binding that the template provides. It appears to me that changing the datacontext of a single element in the flyout is not allowed. So, the way I got around it is to create a selected item in the viewmodel and changed the template code to bind to the selected item on view model. Then bind all elements including the command to the same datacontext for the entire form.

    <ListView
        x:Name="itemListView"
        AutomationProperties.AutomationId="ItemsListView"
        AutomationProperties.Name="Items"
        TabIndex="1"
        Grid.Row="1"
        Margin="-10,-10,0,0"
        Padding="120,0,0,60"
        ItemsSource="{Binding Matches}"
        SelectedItem="{Binding SelectedMatch, Mode=TwoWay}"
        IsSwipeEnabled="False">
        <ListView.ItemTemplate>
            <DataTemplate>

Now the binding works for all fields including the template.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM