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>
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.
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With