How do I tell when a ListViewItem gets focus? - xaml

I have a UWP XAML ListView, and I would like to handle focus events when I switch between items within with arrow keys. However, I cannot figure out how to handle focus events for my items:
<ListView ItemsSource="{x:Bind Items}"
CanDragItems="True" CanReorderItems="True" AllowDrop="True"
SelectionMode="None" IsItemClickEnabled="True" ItemClick="ListView_ItemClick">
<ListView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<!-- Never fires, even with Control.IsTemplateFocusTarget="True" : -->
<StackPanel GotFocus="StackPanel_GotFocus">
<!-- Never fires: -->
<TextBlock Text="{x:Bind}" GotFocus="TextBlock_GotFocus" />
<Button Content="Foo" IsTabStop="False" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<!-- Never fires: -->
<ListViewItemPresenter [...]
GotFocus="Root_GotFocus" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Where else could I listen to get these focus events?
Thanks!
Disclaimer: I work for Microsoft.

When using <ListView> or <ListBox> you don't need to use GotFocus events.
Instead you use SelectionChanged event in the main <listView> control, and in code get the index of the <ListViewItem> that got selected.
SelectionChanged event is triggered every time the user change his selection in the <ListView>.
ListView.SelectedIndex returns the index number of the selected <ListViewItem> First item is 0.
Here is an example:
XAML:
<Image x:Name="img"/>
<ListView x:Name="listView" SelectionChanged="ListView_SelectionChanged">
<ListViewItem>Image 1</ListViewItem>
<ListViewItem>Image 2</ListViewItem>
<ListViewItem>Image 3</ListViewItem>
</ListView>
C#:
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int num = listView.SelectedIndex + 1;
img.Source = new BitmapImage(new Uri($"ms-appx:///Assets/Pictures/image{num}.jpg"));
}

Related

Xaml Internal Error error WMC9999: Object reference not set to an instance of an object

This has come up a few times, and I've been struggling with it all day in a UWP app.
My specific issue was that I was using x:Bind inside a ContentTemplate that was inside a DataTemplate:
<DataTemplate x:DataType="IFactionMember">
<Button Command="{x:Bind **Property of IFactionMember**}"> // Good
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Padding="10,0">
<TextBlock Text="{x:Bind **Property of IFactionMember**}" /> // Bad
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
You cannot do this :(
You could use {Binding} instead for your scenario, for example:
<ListView x:Name="listview" ItemsSource="{x:Bind members}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:IFactionMember">
<Button >
<Button.Template>
<ControlTemplate TargetType="Button" >
<Grid Padding="10,0">
<TextBlock Text="{Binding testtext}" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
x:bind lacks some of the features of {Binding}, in x:Bind, Path is rooted at the Page by default, not the DataContext, it seems like if you are using x:bind here, it will try to find the property at the MainPage, so that it will not find the correct property.

UWP Xaml Relative Panel, Stretch and Other Element

I create UWP Application and using RelativePanel.
I use relative panel.alignwithright, top, left, bottom panel for stretch width to listview.
But after add other element (ex. Stackpanel) to right of listview, other panel do not view in page.
So i remove relativePanel.AlignWithRight, in this case can not width stretch in listview.
What can i do?
Code:
<RelativePanel x:Name="Information" Grid.Row="1">
<ListView x:Name="MyList"
RelativePanel.AlignBottomWithPanel="True"
RelativePanel.AlignTopWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignLeftWithPanel="True">
<ListView.ItemTemplate>
<DataTemplate>
<userControl:SpendListItem_Template Tapped="SpendListItem_Template_Tapped" ></userControl:SpendListItem_Template>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
<Setter Property="Margin" Value="10,0,10,10"></Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
<StackPanel x:Name="TotalInformation" RelativePanel.RightOf="MyList" Width="100">
<TextBlock>Test Data</TextBlock>
</StackPanel>
</RelativePanel>
I am pretty sure you can't do this in pure XAML by just setting the some of the RelativePanel attached properties but you could handle the SizeChanged event of RelativePanel and set the width of the ListView programmatically. It's a one liner:
private void Information_SizeChanged(object sender, SizeChangedEventArgs e)
{
MyList.Width = Information.ActualWidth - TotalInformation.ActualWidth;
}
<RelativePanel x:Name="Information" Grid.Row="1" SizeChanged="Information_SizeChanged">
<ListView x:Name="MyList">
<ListView.ItemTemplate>
<DataTemplate>
<userControl:SpendListItem_Template Tapped="SpendListItem_Template_Tapped" ></userControl:SpendListItem_Template>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
<Setter Property="Margin" Value="10,0,10,10"></Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
<StackPanel x:Name="TotalInformation" RelativePanel.RightOf="MyList" Width="100">
<TextBlock>Test Data</TextBlock>
</StackPanel>
</RelativePanel>

ListView ItemTemplate Grid 100% Width

I have made an ListView ItemTemplate and I want it to be responsive (when orientation changes, for example, the listView item changes in size). I am using a Grid as a control for the inner elements of the grid but it is not behaving. The ListView.ItemContainerStyle has property HorizontalAlignment="Stretch" which is the behaviour I want, and the ItemContainerStyle is the correct width. Inside the Border and Grid I have the same HorizontalAlignment="Stretch" and they are overflowing when the TextBox contained inside has lots of text, and when there is little or no text in the TextBox the Border element shrinks to be smaller than the ItemContainerStyle is showing.
<ListView ItemsSource="{Binding TileStories}" x:Name="cont" Margin="0,10,0,10" Background="{StaticResource CustomResourceBrush}" BorderBrush="{StaticResource CustomResourceBrush}" Foreground="{StaticResource CustomResourceBrush}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Margin" Value="20,10,20,10" />
<Setter Property="Foreground" Value="{StaticResource BTVioletBrush}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Border CornerRadius="20" BorderThickness="0" Width="{Binding ScrollViewerWidth}" Background="White" HorizontalAlignment="Stretch">
<StackPanel Height="160" Orientation="Horizontal">
<Grid Background="black">
<TextBox Text="Example">
</Grid>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Just do this
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Define MinHeight as 0 for ItemContainerStyle
Add to your ItemContainerStyle
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
And I think Width="{Binding ScrollViewerWidth}" is not required. You can remove this.
I didn't exactly find a solution but I did find a workaround. The Grid was being bound with Width="0" if I used {Binding ActualWidth, ElementName=StackPanel, Mode=OneWay} where StackPanel was the panel within the data template. I was poking around the designer in VS2013 and figured out that the Width was 0 because (I am assuming) the items in the data template are drawn one by one and therefore the Width was zero when the first template was drawn and so on and so forth. I haven't explained that very well I guess, but the important thing is the solution:
<PivotItem x:Name="Feed">
....
<Border CornerRadius="20" BorderThickness="0" Background="White" HorizontalAlignment="Stretch">
<StackPanel Height="160" Orientation="Horizontal">
<Grid HorizontalAlignment="Stretch" Width="{Binding ActualWidth, ElementName=Feed, Mode=OneWay}">
........
</Grid>
</StackPanel>
</Border>
...
</PivotItem>
I think that the PivotItem having a non-variable Width meant the Grid had a concrete Width to inherit from.

Tap event not working in windows phone 8 by MVVM

I am trying to fire event on tap of listbox item and get the item clicked but the tap event is not firing, please help.
<ListBox Margin="0,40,0,0"
ItemsSource="{Binding Documents}" IsHitTestVisible="True"
Width="450"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="150" Margin="5"
Width="150" Background="Aqua">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" HorizontalAlignment="Center" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<commands:MvxEventToCommand Command="{Binding OpenFileCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Are you sure the event never get fired? Maybe you were tapping outside the Grid? Listbox item content (the grid in this case) is not stretcing throughout listbox width, it is aligned left by default. To confirm, try to tap at left most area of listbox item and see if the event fired with that.
Assuming the problem is caused by listbox item content not stretching, you can try to set HorizontalContentAlignment="Stretch" to fix it :
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>

How to implement SemanticZoom?

I have an application that it's main page is organized like this:
Grid (LayoutRoot)
VisualStateManager (FullLandscape, FullPortrait, Filled, Snap)
Grid (Back button and page title)
ScrollViewer (FullLandscape View )
StackPanel (Horizontal)
GridView (non grouped GridView)
GridView (grouped GridView)
GridView (non grouped GridView)
GridView (grouped GridView)
GridView (grouped GridView)
ScrollViewer (Snap View)
Grid
ListView (Vertical)
My questions are:
Do I have to provide a SemanticZoom for each page in my application in order for the application to pass certification?
If I want to provide a SemanticZoom for this main page, how do I do it? i.e. where do I insert the SemanticZoom control?
( I read the article: Quickstart: Adding SemanticZoom controls:)
<SemanticZoom.ZoomedOutView>
<!-- Put the GridView for the zoomed out view here. -->
</SemanticZoom.ZoomedOutView>
<SemanticZoom.ZoomedInView>
<!-- Put the GridView for the zoomed in view here. -->
</SemanticZoom.ZoomedInView>
Thanks,
EitanB
It's a bit hard from to understand what you are trying to achieve from what you have written above, but I'll do my best to answer you questions.
1) SemanticZoom usage is not mandatory to pass certification. It's a nice feature that helps you present data in a neat way to the user and when used appropriately is pretty darn cool.
But, it's just a control. Give us some more information about your project and maybe we can help you decide if it will add something extra or not to the application.
Start easy and work into the details later.
2) Download the SemanticZoom example from MSDN and have a look at the code. BAsically it looks like this:
<Page.Resources>
<CollectionViewSource x:Name="cvs2" IsSourceGrouped="true" />
</Page.Resources>
<Grid x:Name="ContentPanel" VerticalAlignment="Top" HorizontalAlignment="Left">
<SemanticZoom x:Name="semanticZoom" VerticalAlignment="Bottom">
<SemanticZoom.ZoomedOutView>
<GridView ScrollViewer.IsHorizontalScrollChainingEnabled="False">
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Group.Key}"
FontFamily="Segoe UI Light"
FontSize="24"/>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid ItemWidth="75" ItemHeight="75" MaximumRowsOrColumns="1" VerticalChildrenAlignment="Center" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="4" />
<Setter Property="Padding" Value="10" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
</GridView.ItemContainerStyle>
</GridView>
</SemanticZoom.ZoomedOutView>
<SemanticZoom.ZoomedInView>
<GridView ItemsSource="{Binding Source={StaticResource cvs2}}" IsSwipeEnabled="True" ScrollViewer.IsHorizontalScrollChainingEnabled="False">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0" HorizontalAlignment="Left" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Image Source="{Binding Image}" Height="60" Width="60" VerticalAlignment="Center" Margin="0,0,10,0"/>
<TextBlock TextWrapping="Wrap" Foreground="{StaticResource ApplicationForegroundThemeBrush}" Width="200" VerticalAlignment="Center" Text="{Binding Title}" HorizontalAlignment="Left" FontFamily="Segoe UI" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text='{Binding Key}' Foreground="{StaticResource ApplicationForegroundThemeBrush}" Margin="5" FontSize="18" FontFamily="Segoe UI Light" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<StackPanel Orientation="Vertical">
<ContentPresenter Content="{TemplateBinding Content}" />
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding GroupItems}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" MaximumRowsOrColumns="3" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Vertical" MaximumRowsOrColumns="1" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<Button Visibility="Collapsed"/>
</GridView>
</SemanticZoom.ZoomedInView>
</SemanticZoom>
</Grid>
and codebehind:
StoreData _storeData = null;
public ScenarioOutput1()
{
InitializeComponent();
_storeData = new StoreData();
List<GroupInfoList<object>> dataCategory = _storeData.GetGroupsByCategory();
cvs1.Source = dataCategory;
}
Thanks for your answer.
I did see the example and it is clear to me. What is not clear to me is: I have on this one page multiple GridViews not just one like in the example. The question that is open in my mind is: Should I follow the example code for each of the GridViews on the page, or is there a way to do it once for the page that will cover all GridViews? Please see the pseudo code below.
Thanks,
EitanB
VisualStateManager (FullLandscape, FullPortrait, Filled, Snap)
Grid (Back button and page title)
ScrollViewer (FullLandscape View )
StackPanel (Horizontal)
<SemanticZoom x:Name="semanticZoom1" VerticalAlignment="Bottom">
<SemanticZoom.ZoomedOutView>
GridView (non grouped GridView)
</SemanticZoom.ZoomedOutView>
<SemanticZoom.ZoomedInView>
GridView (non grouped GridView - Semantic Version)
</SemanticZoom.ZoomedInView>
</SemanticZoom>
<SemanticZoom x:Name="semanticZoom2" VerticalAlignment="Bottom">
<SemanticZoom.ZoomedOutView>
GridView (grouped GridView)
</SemanticZoom.ZoomedOutView>
<SemanticZoom.ZoomedInView>
GridView (grouped GridView - Semantic Version)
</SemanticZoom.ZoomedInView>
</SemanticZoom>
<SemanticZoom x:Name="semanticZoom3" VerticalAlignment="Bottom">
<SemanticZoom.ZoomedOutView>
GridView (non grouped GridView)
</SemanticZoom.ZoomedOutView>
<SemanticZoom.ZoomedInView>
GridView (non grouped GridView - Semantic Version)
</SemanticZoom.ZoomedInView>
</SemanticZoom>
<SemanticZoom x:Name="semanticZoom4" VerticalAlignment="Bottom">
<SemanticZoom.ZoomedOutView>
GridView (grouped GridView)
</SemanticZoom.ZoomedOutView>
<SemanticZoom.ZoomedInView>
GridView (grouped GridView - Semantic Version)
</SemanticZoom.ZoomedInView>
</SemanticZoom>
<SemanticZoom x:Name="semanticZoom5" VerticalAlignment="Bottom">
<SemanticZoom.ZoomedOutView>
GridView (grouped GridView)
</SemanticZoom.ZoomedOutView>
<SemanticZoom.ZoomedInView>
GridView (grouped GridView - Semantic Version)
</SemanticZoom.ZoomedInView>
</SemanticZoom>
ScrollViewer (Snap View)
Grid
ListView (Vertical)
The way to do it is like I posted in my question, i.e. the question was asking if it is the right way and the answer is yes.
EitanB