Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WinRT What can be instead AncestorType?

I want to get the count of a ListView items. But it uses a Template, therefore, I need to use AncestorType, I have a code that in WPF works fine, but in Windows Store Apps 8 not, because there is no AncestorType there, so what can I do instead? How can I make this code works in winRT?

Here is my code:

<ListView ItemsSource="{Binding Users}">
    <ListView.Style>
        <Style TargetType="ListView">
        <Style.Setters>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border BorderThickness="1" BorderBrush="LightGray">
                            <StackPanel>
                                <ScrollViewer>
                                    <ItemsPresenter />
                                </ScrollViewer>
                                <TextBlock Margin="0,4" FontWeight="Bold">
                                    <Run Text="Count: "/>
                                    <Run Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Path=Items.Count, Mode=OneWay}"/>
                                </TextBlock>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>                    
        </Style.Setters>
    </Style>
    </ListView.Style>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ListViewItem IsHitTestVisible="False">
                <StackPanel>
                    <facebookControls:ProfilePicture Height="74" Width="74" ProfileId="{Binding FacebookId}" />
                    <TextBlock Text="{Binding UserName}" FontSize="18" HorizontalAlignment="Center" />
                </StackPanel>
            </ListViewItem>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
like image 868
Misha Zaslavsky Avatar asked Sep 07 '13 08:09

Misha Zaslavsky


3 Answers

The answer which was posted by Ed Chapel has one big disadvantage:

<vm:MyViewModel x:Key="ViewModel" />

leads to that MyViewModel will be constructed one more time. In common scenarios, this is unwanted behavior.

By the way, there is a perfect trick to bind to parent's DataContext without reconstructing a view-model.

Assuming MyViewModel has an 'ICommand' named TestCommand and is current DataContext of a page, which contains your UserControl, set the x:Name of a page and just bind DataContext of a page to a Tag property of UserControl using ElementName binding:

<Page...
    x:Name="rootPage">

    <Grid>
        <controls:MyUserControl Tag={Binding DataContext, ElementName='rootPage'} ... />
    </Grid>

    ...
</Page>

And then in XAML of your UserControl set the x:Name to UserControl and bind your property to a property in Tag:

<UserControl ...
    x:Name="rootControl">

    <Grid>
        <Button Command={Binding Tag.TestCommand, ElementName='rootControl'} ... />
    </Grid>

</UserControl>

That's, possibly, not the cleanest trick, which works because Tag property is a dependency property of type object and you can bind anything to it.

like image 98
Oleksandr Zolotarov Avatar answered Oct 19 '22 09:10

Oleksandr Zolotarov


Simplest solution is to name any root container which has your view model in Context and just set the DataContext of your control/container inside the ContentControl by mentioning element name, and you will get same context.

Example, (I have named my root grid of page as 'rootGrid' and set the context by DataContext="{Binding ElementName=rootGrid, Path=DataContext}" )

<ContentControl Name="contentControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                        >
        <Grid Height="600" 
              Width="600"
                 DataContext="{Binding ElementName=rootGrid, Path=DataContext}"
              > 

            <Image Height="500" Width="500" 

                   Source="{Binding photoUrl}" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
        </Grid>
    </ContentControl>
like image 41
Khurram Avatar answered Oct 19 '22 09:10

Khurram


As you are in a ControlTemplate, you need some way to break out and address the underlying DataContext. It depends on how you defined the object you are binding to. For example, if you defined a ViewModel in the resources, you could access it the same as the Users property:

<UserControl ... >
  <UserControl.Resources>
      <vm:MyViewModel x:Key="ViewModel" />
  </UserControl.Resources>
  ...
    <Grid DataContext="{Binding Source={StaticResource ViewModel}}">
      <ListView ItemsSource="{Binding Users}">
      ...
        <ControlTemplate>
        ...
          <Run Text="{Binding Source={StaticResource ViewModel},
                              Path=Users.Count}"/>

This is one way to deal with that.

like image 1
Ed Chapel Avatar answered Oct 19 '22 07:10

Ed Chapel