listview visual state manager in item template (WinRT, Metro, XAML) - xaml

I am trying to get a listview to display a list of items made up of textblocks...
when the listview item is clicked i would like to show instead a list made up of textboxes...
Below is what i have come up with, it does not work.
I have two grids within the templates and was hoping to simply show and hide the grids depending on if the listview item is selected. Where have i gone wrong?
I ripped these visual states from the listview's template itself but i must admit im not sure how they work, or how they are meant to be triggered. Should there be some code behind to do this?
<ListView Grid.Row="2" ItemsSource="{Binding Lines}" HorizontalAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid Name="Readonly">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding One}" Grid.Column="0"/>
<TextBlock Text="{Binding Two}" Grid.Column="1"/>
</Grid>
<Grid Name="Editing" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding One}" Grid.Column="0"/>
<TextBox Text="{Binding Two}" Grid.Column="1"/>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Editing" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Readonly" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Many thanks,
Kohan

You are setting the Storyboard Animation up outside the Items that are being rendered. The targets you are specifying are not only out of the scope of the outer page, but they potentially do not exist yet. As a result, the Storyboard cannot be setup when the page is rendered.
Here's what you want to do.
Create a user control that will represent the layout you want in your ListView item. When you define your ListView, be sure to include your UserControl in your DataTemplate, like this:
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<local:MyUserControl />
</DataTemplate>
</ListView.ItemTemplate>
</ListView.ItemsPanel>
</ListView>
Now, for the VisualStates. You need to set the states up inside the UserControl. That means a state for Edit and a state for View. A state needs to be localized like this. Think of the Button control. The states in a button are defined in each Button not some shared location.
When you are ready to change the state of one of the items, you need to wire it to your code behind. In your code behind, you need to loop through the items in your ListView and call a method you create, something like MakeStateEdit() and MakeStateView(). It will be your implementation of those methods that sets the states of the user control. The outside code just trusts it to happen.
This means you need to call VisualStateManager.GoToState(this, "Edit", true); (or whatever state you create) inside your UserControl, in the code-behind. Conversely you might set the "View" state when the MakeStateView() is called.
To iterate a ListView Items property, you need to use a technique like this (http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html). You'll find that once you start down this path, it really isn't very complicated. You might be disappointed that you can't do all of this in XAML. You can't. But it can be done!
Best of luck!

I don't know if visual state changes propagate, so maybe your solution should somehow work, but I would edit the visual states in the ListViewItem template instead (through ItemContainerStyle).

Related

How to style a scrollbar to set it's colour and stop it fading out

I am working on a WinRT application and I have a problem with a scrollbar that needs to be made more noticeable on a white background, and needs to stop disappearing.
The user is meant to answer a number of questions displayed by the listview and at present can easily miss that there are more questions off the end of the screen.
So I would like to style my scrollbars accordingly.
What I find out as a newcomer to XAML is that the solutions I have found online involve a huge amount of code and it is hard to work out from that the very simple things that I want to do.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Text="*" FontSize="40" FontWeight="Bold" Foreground="Red"/>
<TextBlock Text=" = Required " FontSize="20"/>
</StackPanel>
<ListView Grid.Row="1"
ItemsSource="{Binding Path=Survey.SelectedSection.Questions, Mode=TwoWay}"
IsSwipeEnabled="False"
SelectionMode="None"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Background="White"
ItemTemplateSelector="{StaticResource ResourceKey=QuestionDisplay}"
ItemContainerStyle=
"{StaticResource ResourceKey=QuestionListViewItemContainerStyle}" />
</Grid>
So how do I set the colour of the scrollbars and stop them from fading out?
I found that I can get the default styles from here: https://msdn.microsoft.com/library/windows/apps/jj710190.aspx
To put my own colours in I just changed the SolidColorBrush elements. And to stop the scrollbar disappearing I commented out;
<VisualState x:Name="NoIndicator">
<Storyboard>
<FadeOutThemeAnimation BeginTime="0" TargetName="HorizontalPanningRoot" />
<FadeOutThemeAnimation BeginTime="0" TargetName="VerticalPanningRoot" />
<FadeOutThemeAnimation BeginTime="0" TargetName="HorizontalRoot" />
<FadeOutThemeAnimation BeginTime="0" TargetName="VerticalRoot" />
</Storyboard>
</VisualState>

Goto VisualState in Listivew item DateTemplate windows phone 8.1

My requirement: when tapped on the border in ListViewItem(DataTemplate) an overlay should appear on top of it with animation.
In my listview data template I defined a visual state at the root. I want to goto the visual state when user taps on the border. I have tried following xaml but it is not working
<DataTemplate x:Key="MyTemplate">
<Grid Background="{Binding ItemBackground}"
Margin="0,0,0,5" Height="auto">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup >
<VisualState x:Name="OverlayState">
<Storyboard >
<DoubleAnimation Storyboard.TargetName="checkedBorder"
Storyboard.TargetProperty="Opacity"
Duration="0"
To="1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Height="auto" Margin="14,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="55"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<!--Image Section" -->
<Grid Height="108" Margin="0,8,0,0" VerticalAlignment="Top">
<Grid Margin="0">
<Border HorizontalAlignment="Left" Margin="0" VerticalAlignment="Bottom" Width="98" Height="98" CacheMode="BitmapCache" CornerRadius="30">
<Border.Background>
<ImageBrush ImageSource="{Binding ImageSource}" Stretch="Fill"></ImageBrush>
</Border.Background>
<i:Interaction.Behaviors>
<icore:EventTriggerBehavior EventName="Tapped">
<icore:GoToStateAction StateName="OverlayState" TargetObject="{Binding ElementName=checkedBorder}"></icore:GoToStateAction>
</icore:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Border>
<!-- Overlay Border -->
<Border HorizontalAlignment="Left" Opacity="0" x:Name="checkedBorder" Margin="0" Background="#99000000" VerticalAlignment="Bottom"
Width="98" Height="98" CacheMode="BitmapCache" CornerRadius="30">
</Border>
</Grid>
</Grid>
</Grid>
</Grid>
</DataTemplate>
This question is more complex than I initially thought.
First, let's correct a few issues in your xaml code.
The following line needs to be removed. It's like saying 'go find a state named OverlayState on the checkedBorder element'. Clearly that state is not on that element. Also, changing the ElementName binding to point to the top level Grid (where the visual state group is) won't work either, I will explain why later.
TargetObject="{Binding ElementName=checkedBorder}"
You should always give your VisualStateGroup a name, like this -
<VisualStateGroup x:Name="MyStates">
You need to set IsHitTestVisible to False on your overlay Border, otherwise the Border with image background will not be able to receive the Tapped event because it's sitting behind the overlay one.
I thought it should be good to go. However, if you run the app now, you will get an unhandled exception saying
Target does not define any VisualStateGroups.
If you add back the TargetObject ElementName binding and change it to point to the top level Grid, the exception will go away but the visual state is not called.
TargetObject="{Binding ElementName=myFirstLevelGridWhereTheVSGroupIs}"
This is because a normal VisualStateManager only works for Controls not FrameworkElements since your Grid is not a type of Control.
In a WP Silverlight app, it's fairly simple to fix. All you need to do is to add a built-in CustomVisualStateManager which allows you to pass in a FrameworkElement on top of the VisualStateGroups definition. But such class doesn't exist in WinRT.
I asked a question about this a while ago and eventually came up with an answer.
Include this class into your project, and add the reference in your xaml code, just before your VisualStateGroups definition.
<VisualStateManager.CustomVisualStateManager>
<local:ExtendedVisualStateManager />
</VisualStateManager.CustomVisualStateManager>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="MyStates">
<VisualState x:Name="OverlayState">
Lastly, because unlike the GoToStateAction in Silverlight app, the WinRT's GoToStateAction doesn't handle CustomVisualStateManager, you will have to create a custom GoToStateAction too.
public class ExtendedGoToStateAction : DependencyObject, IAction
{
public string StateName
{
get { return (string)GetValue(StateNameProperty); }
set { SetValue(StateNameProperty, value); }
}
public static readonly DependencyProperty StateNameProperty =
DependencyProperty.Register("StateName", typeof(string), typeof(ExtendedGoToStateAction), new PropertyMetadata(string.Empty));
public bool UseTransitions
{
get { return (bool)GetValue(UseTransitionsProperty); }
set { SetValue(UseTransitionsProperty, value); }
}
public static readonly DependencyProperty UseTransitionsProperty =
DependencyProperty.Register("UseTransitions", typeof(bool), typeof(ExtendedGoToStateAction), new PropertyMetadata(false));
public object Execute(object sender, object parameter)
{
return ExtendedVisualStateManager.GoToElementState((FrameworkElement)sender, this.StateName, this.UseTransitions);
}
}
And replace the built-in one with this.
<i:Interaction.Behaviors>
<iCore:EventTriggerBehavior EventName="Tapped">
<local:ExtendedGoToStateAction StateName="OverlayState"/>
</Core:EventTriggerBehavior>
You should be able to see the animation working now. :)

Setting the GroupStyle.Panel of a ListView on Windows Phone

I'm trying to create a ListView with grouping where the elements in each group are shown horizontally (as a scrollable content). No matter what I tried with the GroupStyle.Panel of the ListView it doesn't seem to have any effect on the list.
Here is how my XAML looks:
<ListView x:Name="itemListView"
Padding="10"
SelectionMode="None"
IsSwipeEnabled="False"
IsItemClickEnabled="True"
ItemTemplate="{StaticResource listItemTemplate}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<ItemsWrapGrid ItemWidth="144" Orientation="Horizontal" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding DisplayTitle}"
Margin="0,10,0,5"
Foreground="Black"
Style="{StaticResource SubheaderTextBlockStyle}"
TextWrapping="NoWrap" />
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
Where
<Page.Resources>
<DataTemplate x:Key="listItemTemplate">
<Grid Width="144" Margin="5">
<!-- details -->
</Grid>
</DataTemplate>
</Page.Resources>
The following image shows on the left the actual result I get, and on the right what I want to have.
I tried using a ItemsWrapGrid with different properties, I tried a StackPanel and even an VariableSizedWrapGrid, but nothing changed in the way the list items are displayed.
How can this be done?
#kubakista was right about
It looks like if ListView.ItemsPanel contains ItemsStackPanel then
GroupStyle.Panel is ignored...
However, changing this won't solve your problem as -
The scrolling becomes a bit laggy.
There is no horizontal scrolling.
The ListView loses virtualization.
The nice group header rolling up animation is gone.
Here is an alternative without changing the structure of the ListView itself but a little bit modification in your data structure.
The idea is, treat each horizontal list of rectangles under a group as one collection item on the UI.
This means, each group in the ListView will only have one child, which is actually a collection of rectangles that will be presented in an horizontal scrollable ItemsControl.
So, assume you have some collection of type ObservableCollection<Item> as the CollectionViewSource, the Item will now become type of <ObservableCollection<Item>> in order to hold the collection of rectangles. Therefore, the type of the collection will need to be updated to something like ObservableCollection<ObservableCollection<Item>>.
Inside the ListView's ItemTemplate, you will need to create a horizontally scrolling ScrollViewer and put an ItemsControl inside. Make sure you have set the latter's ItemsSource to {Binding}.
To enable horizontal swiping, you will need to disable the tilt effect by editing the default style of ListViewItem and commenting out the following code.
<!--
<VisualStateGroup.Transitions>
<VisualTransition From="Pressed" To="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="TiltContainer"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="Pressed">
<Storyboard>
<PointerDownThemeAnimation Storyboard.TargetName="TiltContainer"/>
</Storyboard>
</VisualState>
-->
I have attached a working sample project here as well as a screenshot shown below.
Hope this helps!

How do you make Windows Store App TextBlock Pressable?

I see many win store apps have this but I couldn't figure out how it's done. Where basically I have TextBlock and it is pressable, by pressing on it something happens. How do you achieve this? Below is what I saw but it doesn't work.
<Grid x:Name="TitleGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Storyboard x:Name="TitlePressAnimation">
<PointerDownThemeAnimation Storyboard.TargetName="TitlePanel" AutoReverse="True" />
</Storyboard>
</Grid.Resources>
<StackPanel x:ConnectionId='4' x:Name="TitlePanel" Orientation="Horizontal" Margin="120,0,0,0">
<TextBlock x:Name="TitleTextBlock" Text="{Binding DisplayName}" Style="{StaticResource TitleStyle}"/>
</StackPanel>
</Grid>
open your app in blend. Click on textblock you have created and click on 'event handlers for selected item'. its located on the top righthand corner beside 'Name'.
now find a property called 'Tapped'. enter any name there such as 'tap' and doule click. this will create and open the function in c# page. Enter code which you want to be executed there.
here is the function created.
private void Tap(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
// Add code here you want to execute when textblock is clicked.
}

windows 8 multiple grid views on hub page

I am currently building a hub page for my application. This page is designed to have multiple columns, each with a header and a gridview below. However, each column (gridview) is populated with a different set of data from my view model. I am successfully populating the grid views, but what i'm seeing is that the horizontal scrolling does not work so I can never view all of the information on the hub page. Basically, users can't horizontally pan.
Is working with grouped data (gridview) the only way to achieve this?
I should also say that I tried using a Scrollviewer, but it seemed to scrunch up my gridviews, where it only showed my data in one column (per gridview).
Please see below at my current XAML code. Thanks & look forward to your responses.
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="CongressWatch.MainPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CongressWatch"
xmlns:common="using:CongressWatch.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
<x:String x:Key="AppName">congress watch</x:String>
</Page.Resources>
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="{StaticResource AppName}" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
<Grid Grid.Row="1" Margin="0,-3,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock x:Name="txtHeadingLegislators"
HorizontalAlignment="Left"
TextWrapping="Wrap"
Text="legislators"
Margin="120,0,0,20"
VerticalAlignment="Top"
Style="{StaticResource PageSubheaderTextStyle}"/>
<GridView
x:Name="grdViewLegislators"
Grid.Row="1"
Margin="120,0,0,50"
ItemsSource="{Binding Legislators, Mode=TwoWay}"
IsItemClickEnabled="True"
SelectionMode="None"
ItemClick="grdViewLegislators_ItemClick"
ItemTemplate="{StaticResource LegislatorGVDataItemTemplate}"/>
<TextBlock x:Name="txtHeadingCommittees"
Grid.Column="1"
HorizontalAlignment="Left"
TextWrapping="Wrap"
Text="committees"
Margin="80,0,0,20"
VerticalAlignment="Top"
Style="{StaticResource PageSubheaderTextStyle}"/>
<GridView
x:Name="grdViewCommittees"
Grid.Row="1"
Grid.Column="1"
Margin="80,0,0,50"
ItemsSource="{Binding Committees, Mode=TwoWay}"
IsItemClickEnabled="True"
SelectionMode="None"
ItemClick="grdViewCommittees_ItemClick"
ItemTemplate="{StaticResource CommitteeGVDataItemTemplate}"/>
<TextBlock x:Name="txtHeadingBills"
Grid.Column="2"
HorizontalAlignment="Left"
TextWrapping="Wrap"
Text="bills"
Margin="80,0,0,20"
VerticalAlignment="Top"
Style="{StaticResource PageSubheaderTextStyle}"/>
</Grid>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state -->
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<!-- The back button and title have different styles when snapped -->
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
The design guidelines are very careful to call out problems with nesting multiple controls inside each other that scroll in the same or even different directions. Not only can you have problems with one control taking events from another, the way the content moves can be undetermined and frustrating for users.
It sounds like you might be trying to implement something similar to the Panorama control on Windows Phone? There is currently no control that works like this on Windows 8. Panorama was created to fit a large amount of data on a small screen by simulating a wider screen. ScrollViewer with stop points can do something similar in Windows 8, but not identical.
I'd take some time to just sit and think about the design of the screen and make sure that's the interaction you want. Take a look at apps like USA Today and see how they deal with grouping on the home page. Granted, every item in their list is a news article.
There is no rule that says every item in every group has to be the same type. You can create one large collection that contains different object types and group them by some shared key. You can also manually create groups and just have a collection of groups.
If you follow either of those approaches, the trick is to tell the GridView to use different data templates for different object types. This is accomplished using a DataTemplateSelector. Here is a good blog post on using DataTemplateSelectors in WinRT:
http://www.comyoucom.com/implementing-a-custom-datatemplateselector-in-winrt/