I am looking at the windows 8 grid project that comes with VS2012 and trying to understand it. I don't know too much about XAML so I getting quite easily lost of where binding code is happening and such.
<Page.Resources>
<!--
Collection of grouped items displayed by this page, bound to a subset
of the complete item list because items in groups cannot be virtualized
-->
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"
ItemsPath="TopItems"
d:Source="{Binding AllGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
</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>
<!-- Horizontal scrolling grid used in most view states -->
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="2"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="1,0,0,6">
<Button
AutomationProperties.Name="Group Title"
Click="Header_Click"
Style="{StaticResource TextPrimaryButtonStyle}" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
<TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>
</StackPanel>
</Button>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
<!-- Vertical scrolling list only used when snapped -->
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemListView"
AutomationProperties.Name="Grouped Items"
Grid.Row="1"
Visibility="Collapsed"
Margin="0,-10,0,0"
Padding="10,0,0,60"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard80ItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="7,7,0,0">
<Button
AutomationProperties.Name="Group Title"
Click="Header_Click"
Style="{StaticResource TextPrimaryButtonStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
<TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>
</StackPanel>
</Button>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
<!-- 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" Text="{StaticResource AppName}" Grid.Column="1" IsHitTestVisible="false" Style="{StaticResource PageHeaderTextStyle}"/>
</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>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Padding">
<DiscreteObjectKeyFrame KeyTime="0" Value="96,137,10,56"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<!--
The back button and title have different styles when snapped, and the list representation is substituted
for the grid displayed in all other view states
-->
<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>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
The first area I don't understand is this
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"
ItemsPath="TopItems"
d:Source="{Binding AllGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
I don't get where this Source="{Binding Groups}" is actually coming from (I am not even sure how to find the code F12 does not work).
Same with the d:Source not sure 100% what is going on there as well.
The next part is in the gridview and again with the binding.
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="2"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
I see that Items Source is using that groupItemsViewSource but not sure how it is parsing the data into the grid look but not sure how.
The next part I don't get is how does it figure out what layout to use. I see this in the comments
<!-- Horizontal scrolling grid used in most view states -->
<!-- Vertical scrolling list only used when snapped -->
I am sure if I look even deeper into it I will find more I don't understand but maybe when I understand this stuff I will understand more(especially once I understand this binding stuff)
I don't get where this Source="{Binding Groups}" is actually coming
from (I am not even sure how to find the code F12 does not work).
Note at the top of the page:
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
which sets the context for the binding on that page to the DefaultViewModel property of the page. In the code behind for the page you'll see
this.DefaultViewModel["Groups"] = sampleDataGroups;
where sampleDataGroups is a list (IEnumerable) of groups (type SampleDataGroup) returned from a method call. Now you also have,
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"
ItemsPath="TopItems"
d:Source="{Binding AllGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
and here "Groups" refers to the key that indexes the DefaultViewModel, so it's going to use that subset of the DefaultViewModel. Furthermore, each item in the CollectionViewSource itself contains a collection, and those collections are surfaced to the binding engine at whatever property ItemsPath specifies, namely, TopItems.
Now from the GridView binding:
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="2"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
you noted that the data is coming from that specific instance of a CollectionViewSource named groupedItemsViewSource (which in this case is equivalent to this.DefaultViewModel["Groups"]). If you look at the header template a bit later, you'll see:
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
...
The Title binding refers to the property of an element in the ItemsSource collection, so this.DefaultViewModel["Groups"][i].Title
ItemTemplate="{StaticResource Standard250x250ItemTemplate}" in the GridView binding governs how the inner collection items are displayed. You'll have to crack that style open (in Common/StandardStyles.xaml) to see that it references properties of a SampleDataItem, essentially leading to this.DefaultViewModel["Groups"][i].TopItems[j].
The d: prefix refers to design time data (well, a namespace that includes classes that manage it); it's what allows you do see the data in the designer without running your application. So at design time the data you are seeing actually comes from SampleDataSource.AllGroups.
As for the comments about scrolling, that gets into the VisualStateManager, each state essentially being a different take on the UI; states transition via a bit of code you can find inside of LayoutAwarePage.cs look for GotoState.
I don't get where this Source="{Binding Groups}" is actually coming from
Bindings target the DataContext of the element -- to find it, you typically scan up the XAML to find where DataContext was last set. So in this case, it must either set on the Page element somehow. (The DataContext can also be set from code-behind, although I'd be surprised if that were the case in the VS sample project.)
Same with the d:Source not sure 100% what is going on there as well.
The d prefix is referring to design-time data. Check for the SampleDataSource, that's where you'll find the design-time instance of AllGroups.
not sure how it is parsing the data into the grid
The Grid auto-generates its columns based on the properties of its row data type.
Related
I am making a UWP app and I have come across a problem. I want to make a StackPanel which hosts two ComboBoxes and one TextBox. I can show it in the app if I create it inside the Grid and it works as expected. But for smaller screen devices I want to show a Button in place of the StackPanel and move the StackPanel to the button flyout.
I have tried to add the StackPanel to a ContentControl and then set it as the Flyout but it doesn't work. Flyout needs a FlyoutPresenter control to be able to show the flyout.
I don't want to create multiple StackPanel controls because of the naming collisions, but I do want it simple so I need to make changes to one side of the controls and when the user switches the screen or the view the smaller screen also shows the same stuff.
Can someone help me here? Maybe just point me in the right direction so I can figure it out on my own. Any help will be appreciated. Thanks
StackPanel control:
<StackPanel Orientation="Vertical"
x:Name="PageOptionsPanel"
HorizontalAlignment="Right">
<AppBarButton Label="Refresh"
Icon="Refresh"
Tapped="PageOptions_Tapped"/>
<RelativePanel Margin="10,0">
<TextBlock Text="Sort by:"
Name="SortText"
RelativePanel.AlignVerticalCenterWithPanel="True"
Margin="0,0,5,0"/>
<ComboBox RelativePanel.RightOf="SortText"
x:Name="MSortingBox"
ItemsSource="{Binding EnSortList}"
RelativePanel.AlignVerticalCenterWithPanel="True"
SelectionChanged="MSortingBox_SelectionChanged"
Width="120"/>
</RelativePanel>
<RelativePanel Margin="10,0">
<TextBlock Text="Country: "
Name="CountryText"
RelativePanel.AlignVerticalCenterWithPanel="True"
Margin="0,0,5,0"/>
<ComboBox RelativePanel.RightOf="CountryText"
x:Name="MCountryBox"
ItemsSource="{Binding EnCountryList}"
RelativePanel.AlignVerticalCenterWithPanel="True"
SelectionChanged="MCountryBox_SelectionChanged"
Width="120"/>
</RelativePanel>
</StackPanel>
Flyout control:
<Button>
<Button.Flyout>
<Flyout Placement="Left"
x:Name="MOptionsFlyout"
Content="{StaticResource PageOptionsFlyout}"
Opened="MOptionsFlyout_Opened">
</Flyout>
</Button.Flyout>
</Button>
If I understand your question correctly, you want to share the XAML for your Options layout between the main page and a flyout, based on the size of the page (for phone vs tablet). You can do this by creating a DataTemplate with the layout and adding it to the page's resource dictionary. Then it can be referenced in multiple places.
Here's the code below that does that. It also hides and shows the pieces based on adaptive triggers.
<Page.Resources>
<DataTemplate x:Key="PageOptionsTemplate">
<StackPanel
x:Name="PageOptionsPanel"
HorizontalAlignment="Right"
Orientation="Vertical">
<AppBarButton
Icon="Refresh"
Label="Refresh" />
<RelativePanel Margin="10,0">
<TextBlock
Name="SortText"
Margin="0,0,5,0"
RelativePanel.AlignVerticalCenterWithPanel="True"
Text="Sort by:" />
<ComboBox
x:Name="MSortingBox"
Width="120"
RelativePanel.AlignVerticalCenterWithPanel="True"
RelativePanel.RightOf="SortText"/>
</RelativePanel>
<RelativePanel Margin="10,0">
<TextBlock
Name="CountryText"
Margin="0,0,5,0"
RelativePanel.AlignVerticalCenterWithPanel="True"
Text="Country: " />
<ComboBox
x:Name="MCountryBox"
Width="120"
RelativePanel.AlignVerticalCenterWithPanel="True"
RelativePanel.RightOf="CountryText"
/>
</RelativePanel>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Name="OptionsFlyoutButton" Content="Show Me" Visibility="Collapsed">
<Button.Flyout>
<Flyout>
<ContentControl ContentTemplate="{StaticResource PageOptionsTemplate}"/>
</Flyout>
</Button.Flyout>
</Button>
<ContentControl Name="OptionsInLine" Visibility="Visible" ContentTemplate="{StaticResource PageOptionsTemplate}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="320"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="OptionsInLine.Visibility" Value="Collapsed"/>
<Setter Target="OptionsFlyoutButton.Visibility" Value="Visible"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720"/>
</VisualState.StateTriggers>
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1024"/>
</VisualState.StateTriggers>
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
You can also move the DataTemplate out to the application level ResourceDictionary, so that it can be shared between multiple pages.
Finally, another option is to create a user control (using the uwp item template) for this. I recommend creating that if you needed more control over the layout, wanted to encapsulate the logic too, and share it across multiple apps.
For your example, the shared DataTemplate is the easiest path.
Just do this:
<Button Content="Show Me">
<Button.Flyout>
<Flyout>
<StackPanel
x:Name="PageOptionsPanel"
HorizontalAlignment="Right"
Orientation="Vertical">
<AppBarButton
Icon="Refresh"
Label="Refresh" />
<RelativePanel Margin="10,0">
<TextBlock
Name="SortText"
Margin="0,0,5,0"
RelativePanel.AlignVerticalCenterWithPanel="True"
Text="Sort by:" />
<ComboBox
x:Name="MSortingBox"
Width="120"
RelativePanel.AlignVerticalCenterWithPanel="True"
RelativePanel.RightOf="SortText"/>
</RelativePanel>
<RelativePanel Margin="10,0">
<TextBlock
Name="CountryText"
Margin="0,0,5,0"
RelativePanel.AlignVerticalCenterWithPanel="True"
Text="Country: " />
<ComboBox
x:Name="MCountryBox"
Width="120"
RelativePanel.AlignVerticalCenterWithPanel="True"
RelativePanel.RightOf="CountryText"
/>
</RelativePanel>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
to get this:
When using the you get an auto display flyout that is shown whenever a user clicks the button, no code needed.
but to add content to that flyout, you need to have another element in it, then the stackpanel goes into it.
Hope this helps you.
I am trying to create a user control similar to a stock ticker. It will slowly scroll the items to the left. So far I am unable to get something going because:
I am new to WPF/XAML and everywhere I search seems to apply to
silvelight
I am using an ItemTemplate within a ItemsControl, and cant find any
examples showing how to add a storyboard for a item within an item template.
here is my XAML:
<UserControl x:Class="WpfApplication.Ctrls.MessageTicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:ctrls="clr-namespace:WpfApplication.Ctrls"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Background="Honeydew">
<ItemsControl ItemsSource="{Binding}" Name="_items">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="_panel">
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Grid.RenderTransform).(TranslateTransform.X)"
Storyboard.TargetName="_panel"
From="0"
To="360"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Word}" Grid.Column="0" Margin="0" FontWeight="Normal" FontFamily="Segoe UI Semibold"/>
<TextBlock Text="{Binding Path=Percent}" Grid.Column="1" Margin="5,0,3,0" FontFamily="Segoe UI Mono" Foreground="Blue"/>
<Polygon Points="0,10 5,0 10,10" Stroke="Black" Fill="Green" Grid.Column="2" Margin="0,3,10,0"/>
<Polygon Points="5,10 10,0 0,0" Stroke="Black" Fill="Red" Grid.Column="2" Visibility="Collapsed"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
From what I have read, I should be putting the storyboard within the template. When I add a new item to the ItemsControl, nothing happens. I need to have it start at the end of the ItemsControl and scroll to the right all the way to the beginning of the ItemsControl.
Ok so you're close, but you're missing some key things that might explain why it's not firing as you'd expect.
So your first issue lies with how you're using _panel. We'll want to actually move that to an RenderTransform on this Grid that's acting as your parent.
So instead of;
<Grid x:Name="_panel">
We'll say;
<Grid>
<Grid.RenderTransform>
<TranslateTransform x:Name="_panel">
</Grid.RenderTransform>
...
Because your TargetProperty setting in your storyboard isn't going to magically append that Transform on demand like it looks you're thinking it might (at least I've never seen it done that way I don't think).
So we have that, now let's go talk to that Transform via your Storyboard and have it talk to an actual property of your Transform thusly;
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="X"
Storyboard.TargetName="_panel">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="360" />
</DoubleAnimation>
</Storyboard>
So what we're doing is basically saying "HEY _panel, guess what? You get to animate, and before you start I want you to know you're moving 360 across your X axis"
We could add a keytime here to make this happen over more keyframes to allow it to fill in the blanks of an actual animation sequence (your ticker anime, hint hint) but for now, we're just telling that bugger to move.
Other than that, you should work. Hope this helps, cheers.
Oh and PS, you'd be surprised how much XAML can work between WPF/SL/WP, etc. etc. if you just know the fundamentals. Best of luck!
I have a ContentControl that I'm styling with a DataTemplate. I'd like to be able to define an animation outside of the ContentControl that animates elements in the DataTemplate. This XAML is a small, simplified example of my scenario:
<UserControl x:Class="StoryboardTesting.Stage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Key="MyControlTemplate">
<StackPanel>
<TextBlock x:Name="TheBlock1" Text="Foo!" />
<TextBlock x:Name="TheBlock2" Text="Bar!" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValueStates">
<VisualState Name="ToState">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MyContentControl"
Storyboard.TargetProperty="(UIElement.Opacity)"
Duration="0:0:1"
To="0" />
</Storyboard>
</VisualState>
<VisualState Name="FromState" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Canvas>
<ContentControl x:Name="MyContentControl"
ContentTemplate="{StaticResource MyControlTemplate}" />
</Canvas>
</Grid>
</UserControl>
I'd like the animation to be able to target either TextBox in the template (instead of "MyContentControl"), either by position or name. I'm starting the animation in the UserControl's code-behind with a call like this:
VisualStateManager.GoToElementState(this, "ToState", true);
When I run this (replacing "MyContentControl" with "TheBlock"), I get the following:
InvalidOperationException: 'TheBlock1' name cannot be found in the name scope of 'StoryboardTesting.Stage'.
Which makes sense. Is there a way to address either block using property names? I need to avoid codebehind since this is XAML that is being generated at runtime.
I'd highly suggest you to learn using Blend when working on WPF projects. While XAML by keyboard skills are indeed useful, Blend is also very helpful. It took me about 5 minutes to build the following example for you, it's a DataTemplate which has states.
(first I created an empty DataTemplate, then I edited in Blend)
User can press any of the 2 buttons on the bottom and the current state will be changed.
As you'll see below, behaviors proven to be really helpful for handling states, no code-behind at all.
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:wpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow"
Width="525"
Height="350">
<Window.Resources>
<wpfApplication3:MyObject x:Key="MyObject1" />
<DataTemplate x:Key="Template1" DataType="wpfApplication3:MyObject">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="37*" />
<RowDefinition Height="13*" />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="Red">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="button" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="Red" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Green">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="button" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="Lime" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Button x:Name="button"
Grid.RowSpan="1"
Grid.ColumnSpan="2"
Width="100"
Height="100"
Margin="2"
Content="Button"
FontSize="26.667" />
<Button Grid.Row="1"
Width="Auto"
Margin="2"
Content="State1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction StateName="Red" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Grid.Row="1"
Grid.Column="1"
Width="Auto"
Margin="2"
Content="State2">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction StateName="Green" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl Content="{StaticResource MyObject1}" ContentTemplate="{StaticResource Template1}" />
</Grid>
</Window>
Code-behind:
namespace WpfApplication3
{
public partial class MainWindow
{
public MainWindow() {
InitializeComponent();
}
}
internal class MyObject
{
public string Category { get; set; }
public int Value { get; set; }
}
}
EDIT
To answer the point of your question, those states belong to the DataTemplate; defining these states outside of it doesn't make any sense and as you've experienced it is not even possible, and this is for a good reason !
Imagine that you use this template in 2 different places, would they share the same state ? Of course no, so the states have to be defined inside it, not outside.
I am developing a windows 8 application and I want to add a progress bar to my pages when navigating from one to another since users will have to wait in order for the data to be loaded from the server. Can anyone provide me with the code that I need to add in XAML and C#? What property or event of the progress bar should be used?
//XAML PAGE
<common:LayoutAwarePage
x:Name="Hub1"
x:Class="App1.GroupedItemsPage1"
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:App1"
xmlns:data="using:App1.Data"
xmlns:common="using:App1.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.BottomAppBar>
<AppBar>
<Grid>
<Button x:Name="Content_Hub" Height="64" Margin="45,10,0,10" Width="145" Content="CONTENT HUB" FontSize="12" FontFamily="Segui" Click="Content_Hub_Click"/>
<Button x:Name="MARKET_RESEARCH" Height="64" Margin="220,10,0,10" Width="145" Content="MARKET RESEARCH" FontSize="12" FontFamily="Segui" Click="MARKET_RESEARCH_Click"/>
<Button x:Name="LEAD_CONVERSION" Height="64" Margin="400,10,0,10" Width="145" Content="LEAD CONVERSION" FontSize="12" FontFamily="Segui"/>
<StackPanel x:Name="RightPanel" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
<Button x:Name="Help" Style="{StaticResource HelpAppBarButtonStyle}" Tag="Help"/>
<StackPanel.ChildrenTransitions>
<TransitionCollection>
<AddDeleteThemeTransition/>
</TransitionCollection>
</StackPanel.ChildrenTransitions>
</StackPanel>
</Grid>
</AppBar>
</Page.BottomAppBar>
<Page.Resources>
<!--
Collection of grouped items displayed by this page, bound to a subset
of the complete item list because items in groups cannot be virtualized
-->
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"
ItemsPath="TopItems"
d:Source="{Binding AllGroups, Source={d:DesignInstance Type=data:DataSource, IsDesignTimeCreatable=True}}"/>
</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>
<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}" Margin="36,0,0,36" Grid.Row="0"/>
<StackPanel x:Name="Header" Grid.Row="0" Grid.Column="1" >
<StackPanel Orientation="Horizontal">
<Image HorizontalAlignment="Left" Height="Auto" Margin="35,30,0,0" VerticalAlignment="Top" Width="202" Source="Assets/ACE-Logo.png"></Image>
</StackPanel>
</StackPanel>
</Grid>
<ProgressRing x:Name="progressBar" VerticalAlignment="Top" />
<!-- Horizontal scrolling grid used in most view states -->
<SemanticZoom Name="Zoom" Grid.Row="1">
<SemanticZoom.ZoomedInView>
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.Row="1"
Margin="0,-3,0,0"
Padding="116,0,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="1,0,0,6">
<Button
AutomationProperties.Name="Group Title"
Content="{Binding Title}"
Style="{StaticResource TextButtonStyle}"
/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<GridView x:Name="ZoomedOutGV" VerticalAlignment="Center">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Group.Title}" Width="200" Height="200" Foreground="Blue"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
</StackPanel>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
<!-- Vertical scrolling list only used when snapped -->
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemListView"
AutomationProperties.Name="Grouped Items"
Visibility="Collapsed"
Margin="0,135,0,0"
Padding="10,0,0,60"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard80ItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick" Grid.RowSpan="2">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="7,7,0,0">
<Button
AutomationProperties.Name="Group Title"
Content="{Binding Title}"
Style="{StaticResource TextButtonStyle}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
<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>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Padding">
<DiscreteObjectKeyFrame KeyTime="0" Value="96,0,10,56"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<!--
The back button and title have different styles when snapped, and the list representation is substituted
for the grid displayed in all other view states
-->
<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>-->
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</common:LayoutAwarePage>
//C# Page
using App1.Data;
using App1.DataService;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Grouped Items Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234231
namespace App1
{
/// <summary>
/// A page that displays a grouped collection of items.
/// </summary>
public sealed partial class GroupedItemsPage1 : App1.Common.LayoutAwarePage
{
public GroupedItemsPage1()
{
this.InitializeComponent();
}
/// <summary>
/// Populates the page with content passed during navigation. Any saved state is also
/// provided when recreating a page from a prior session.
/// </summary>
/// <param name="navigationParameter">The parameter value passed to
/// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
/// </param>
/// <param name="pageState">A dictionary of state preserved by this page during an earlier
/// session. This will be null the first time a page is visited.</param>
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var sampleDataGroups = DataSource.GetGroups((String)navigationParameter);
this.DefaultViewModel["Groups"] = sampleDataGroups;
var tracks = groupedItemsViewSource.View.CollectionGroups;
(Zoom.ZoomedOutView as GridView).ItemsSource = tracks;
// GetSectors();
}
/// <summary>
/// Invoked when an item within a group is clicked.
/// </summary>
/// <param name="sender">The GridView (or ListView when the application is snapped)
/// displaying the item clicked.</param>
/// <param name="e">Event data that describes the item clicked.</param>
/*protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
var client = new DataServiceSoapClient();
var sectors = await client.GetSectorsAsync(1);
this.DefaultViewModel["sectors"] = sectors;
}*/
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
// Navigate to the appropriate destination page, configuring the new page
// by passing required information as a navigation parameter
var itemId = ((DataItem)e.ClickedItem).UniqueId;
this.Frame.Navigate(typeof(GroupDetailPage1), itemId);
}
private void Content_Hub_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(App1.GroupedItemsPage1));
}
private void MARKET_RESEARCH_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(App1.SamplePage));
}
}
}
In LoadState load your data asynchronous. Set ProgressBar (or ProgressRing) visibility to Visible and hide main content grid, after you get data show content grid and hide progressbar.
protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
ProggressBarVisible(true);
try
{
MainContentGrid.Visibility = Visibility.Collapsed;
this.DataContext = await MyDataSource.GetData(navigationParameter);
}
finally
{
ProggressBarVisible(false);
MainContentGrid.Visibility = Visibility.Visible;
}
}
private void ProggressBarVisible(bool visible)
{
ProgressRingLoad.Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
ProgressRingLoad.IsActive = visible;
}
And XAML for empty page should look something like this :
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="WindowsStorePlayground.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WindowsStorePlayground"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="MainContentGrid">
<!-- page content goes here -->
</Grid>
<ProgressRing x:Name="ProgressRingLoad" Visibility="Collapsed"></ProgressRing>
</Grid>
</common:LayoutAwarePage>
btw. to get LoadState you should use LayoutAwarePage
if you are loading the data async than add this to your function
private async void LoadDataAsync()
{
//progressbar start
progressBar.IsIndeterminate = true;
//Some async calls
//other stuff
//stop progressbar
progressBar.IsIndeterminate = false;
}
Your problem is that you fetch your data in either the page constructor, the OnNavigatedTo-event or the Loaded-event. All block displaying the page. So you have to find another solution. I see two there:
1.Load your data later. Defer the loading, and you can display the page with a progressring or similar
<ProgressRing x:Name="PrgRing" IsActive="True" Visibility="Collapsed"/>
and in your OnNavigatedTo-handler
PrgRing.Visibility = Visibility.Visible;
then load your data, and when you're finished, display it and set
PrgRing.Visibility = Visibility.Collapsed;
2.Use a page in-between, which loads your data and displays a progressring.
XAML:
<ProgressRing x:Name="PrgRing" IsActive="True" Visibility="Collapsed"/>
C#
//load the data and then
this.rootFrame.Navigate(typeof(TargetPage));
I have a ScrollViewer that contains a StackedPanel with rectangles laid out horizontally. I want to be able to scroll horizontally, but this isn't happening for me. Here is my XAML:
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="BlastSwing.GroupedItemsPage"
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:BlastSwing"
xmlns:data="using:BlastSwing.Data"
xmlns:common="using:BlastSwing.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!--
Collection of grouped items displayed by this page, bound to a subset
of the complete item list because items in groups cannot be virtualized
-->
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"
ItemsPath="TopItems"
d:Source="{Binding AllGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
</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 -->
<TextBlock x:Name="pageTitle" Text="Blast Swing" Style="{StaticResource PageHeaderTextStyle}" Margin="40,0,-10,53"/>
<ScrollViewer HorizontalAlignment="Left" Height="628" Grid.Row="1" VerticalAlignment="Top" Width="1366" RenderTransformOrigin="0.476999998092651,0.998000025749207" VerticalScrollMode="Disabled" Margin="-22,0,0,0" HorizontalScrollMode="Auto">
<StackPanel Height="568" Width="1313" RenderTransformOrigin="-0.0179999992251396,0.512000024318695" Orientation="Horizontal">
<Rectangle Fill="#FF974B55" Height="568" Stroke="Black" VerticalAlignment="Top" Width="371"/>
<Rectangle Fill="#FF17179C" Height="568" Stroke="Black" VerticalAlignment="Top" Width="371"/>
<Rectangle Fill="#FF8D2B80" Height="568" Stroke="Black" VerticalAlignment="Top" Width="371"/>
<Rectangle Fill="#FF301D2F" Height="568" Stroke="Black" VerticalAlignment="Top" Width="371"/>
<Rectangle Fill="#FFF4F4F5" Height="568" Stroke="Black" VerticalAlignment="Top" Width="371"/>
</StackPanel>
</ScrollViewer>
<!-- Back button and page title -->
<!-- Horizontal scrolling grid used in most view states -->
<!-- Vertical scrolling list only used when snapped -->
<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"/>
<!--
The back button and title have different styles when snapped, and the list representation is substituted
for the grid displayed in all other view states
-->
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</common:LayoutAwarePage>
You are setting Scrollviewer's Width="1366" which is more than your child stackpanel Width="1313".
If you want to see the horizontal scrollbar then you might want to set the size of ScrollViewer less than 1313 and it should be able to display the horizontal scrollbar as it is not able to display the content fully.
Set the HorizontalScrollBarVisibility property on the ScrollViewer to Visible or Auto.
You are setting the Width of your StackPanel manually and it is less than the total of its children.