WinRT What can be instead AncestorType?
Asked Answered
N

4

7

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>
Nelidanelie answered 7/9, 2013 at 8:41 Comment(1)
I shared a solution for RelativeSource AncestorType in UWP over at https://mcmap.net/q/925131/-uwp-equivalent-function-to-findancestor-in-uwpBrainsick
B
1

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.

Biogenesis answered 7/9, 2013 at 10:1 Comment(2)
I am in a ControlTemplate, that's why I wanted the AncestorType, can you advise what I can do instead?Nelidanelie
Thanks, just needed to change the Path to Users.Count (no need for the Source)...Nelidanelie
D
8

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.

Dimitry answered 6/2, 2014 at 9:50 Comment(0)
M
5

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>
Myxomatosis answered 21/5, 2014 at 7:51 Comment(0)
B
1

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.

Biogenesis answered 7/9, 2013 at 10:1 Comment(2)
I am in a ControlTemplate, that's why I wanted the AncestorType, can you advise what I can do instead?Nelidanelie
Thanks, just needed to change the Path to Users.Count (no need for the Source)...Nelidanelie
G
0

I got it like this in UWP

<GridView x:Name="abc" ItemsSource="{Binding Path=DataContext.Companies,RelativeSource={RelativeSource Mode=TemplatedParent}}"></GridView>
Guileless answered 12/5, 2016 at 12:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.