(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

WP7 Stock Quoting Demo Series Part 2

(1 votes)
John McFetridge
>
John McFetridge
Joined Feb 12, 2010
Articles:   5
Comments:   0
More Articles
0 comments   /   posted on Sep 20, 2010
Tags:   windows-phone-7 , john-mcfetridge
Categories:   Windows Phone

This article is compatible with the latest version of Silverlight for Windows Phone 7.

Watch video accompanying this article!

This article is Part 2 of the series WP7 Stock Quote Demo.

In Part 1 we started the development of our Stock Quote application and used MVVM Light to add a command handler for the Add button that the user will use to add symbols to monitor. Now we continue the process by changing the ListView so each row will look like:

When the user touches the + button then a grey rectangle with the Volume, Ask etc is displayed with additional quote information.

To achieve this look we modify the XAML that was generated for us as we want to present the quotes in a ListBox so we change the XAML for the listbox:

<ListBox x:Name="Quotes" ItemsSource="{Binding Path=quotesList}" ItemTemplate="{StaticResource QuoteTemplate}">

The Listbox rows are bound to the quotesList that we added to the ViewModel and I have moved the template that controls the appearance of each quote to the resource section:

 <DataTemplate  x:Key="QuoteTemplate" >
             <StackPanel Name="QuoteContainer"    Orientation="Vertical" >
                 <Grid  Width="500" >
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="90"></ColumnDefinition>
                         <ColumnDefinition Width="140"></ColumnDefinition>
                         <ColumnDefinition Width="90"></ColumnDefinition>
                         <ColumnDefinition Width="40"></ColumnDefinition>
                         <ColumnDefinition Width="40"></ColumnDefinition>
                         <ColumnDefinition Width="40"></ColumnDefinition>
                     </Grid.ColumnDefinitions>
   
        <TextBlock Style="{StaticResource VisText}" Grid.Column="0" Text="{Binding Path= Symbol}" />
        <TextBlock Style="{StaticResource VisText}"  Grid.Column="1"  Text="{Binding Path=Time,Converter={StaticResource ToShortTime}}" />
        <TextBlock Style="{StaticResource VisText}"  Grid.Column="2"  Text="{Binding Path=Trade}" />
   
        <Grid   Grid.Column="3" Height="20"  Width="30">
              <Path x:Name="DownArrow"   Canvas.Top="0" Stretch="Fill"      (Note 1)  Visibility="{Binding Path=Direction,Converter={StaticResource ShowDown}}"
                  Fill="Red" Data="{StaticResource DownArrow}"/>
        </Grid>
        <Grid  Grid.Column="3" Height="20"  Width="30" Visibility="{Binding Path=Direction,Converter={StaticResource ShowUp}}">
                <Path x:Name="UpArrow"   Canvas.Left="0" Canvas.Top="0" Stretch="Fill"  (1)   
                       Fill="Green"    Data="{StaticResource UpArrow}" />
        </Grid>
  <Button  x:Name="DisplayMore" Grid.Column="5" Content="+"   Click="this_Click"  Style="{StaticResource ButtonStyle1}"></Button>
                 </Grid>
 <!—This Grid is originally hidden and only displayed with an animation when the DisplayMore button is touched >
  <Grid Name="More"  Background="#FF6C6C73" Height="0">    (Note 2)
          <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="100"></ColumnDefinition>
                 <ColumnDefinition Width="100"></ColumnDefinition>
                 <ColumnDefinition Width="20"></ColumnDefinition>
                 <ColumnDefinition Width="100"></ColumnDefinition>
                 <ColumnDefinition Width="90"></ColumnDefinition>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
                 <RowDefinition Height="30"/>
                 <RowDefinition Height="30"/>
                 <RowDefinition Height="30"/>
          </Grid.RowDefinitions>
  
         <TextBlock Grid.Row="0"  Grid.Column="0"    Text="Volume: " ></TextBlock>
                     <TextBlock Grid.Row="0"  Grid.Column="1" Style="{StaticResource HidText}"    Text="{Binding Path=Volume}"/>
                     <TextBlock Text="Ask: " Grid.Row="1"  Grid.Column="0" ></TextBlock>
                     <TextBlock Grid.Row="1"  Grid.Column="1"  Style="{StaticResource HidText}"    Text="{Binding Path=Ask}"   />
                     <TextBlock Text="Bid:" Grid.Row="2"  Grid.Column="0" ></TextBlock>
                     <TextBlock  Grid.Row="2"  Grid.Column="1" Style="{StaticResource HidText}"    Text="{Binding Path=Bid}"  />
                     <TextBlock Grid.Row="0"  Grid.Column="3"    Text="Day High: " ></TextBlock>
                     <TextBlock Grid.Row="0"  Grid.Column="4" Style="{StaticResource HidText}"    Text="{Binding Path=DayHi}" />
                     <TextBlock Text="Day Low: " Grid.Row="1"  Grid.Column="3" ></TextBlock>
                     <TextBlock Grid.Row="1"  Grid.Column="4"  Style="{StaticResource HidText}"    Text="{Binding Path=DayLow}"   />
                     <TextBlock Text="Year High:" Grid.Row="2"  Grid.Column="3" ></TextBlock>
                     <TextBlock  Grid.Row="2"  Grid.Column="4" Style="{StaticResource HidText}"    Text="{Binding Path=YrHi}"  />
                 </Grid>
             </StackPanel>
         </DataTemplate>
   

This Xaml divides the row into columns that will contain the text for the Symbol, the time of trade and the volume. The directional arrows are draw with a points generated by Blend where the path is contained a string resource so I can reuse this in other projects:

<sys:String x:Key="DownArrow">F1 M 6.00876,1.43051e-006L 1.99995,1.43051e-006L 1.99995,4.00001L 6.35783e-007,4.00001L 6.35783e-007,4.50441L 3.50442,8L 4.5044,8L 8.00882,4.50441L 8.00882,4.00001L 6.00876,4.00001L 6.00876,1.43051e-006</sys:String>

<sys:String x:Key="UpArrow">F1 M 4.50439,4.76837e-007L 3.49561,4.76837e-007L -7.15784e-006,3.4956L -7.15784e-006,4.00001L 2.00005,4.00001L 2.00005,8L 5.99995,8L 5.99995,4.00001L 8,4.00001L 8,3.4956L 4.50439,4.76837e-007</sys:String>

Only one of the arrows are displayed a time and this is controlled by the Directional Value converters whose definition was added to the resource:

<local:UpDirectionConverter x:Key="ShowUp"/>
<local:DownDirectionConverter x:Key="ShowDown"/>

The code for these converters controls the visibility of the arrow as in this XAML:

<Path x:Name="DownArrow"   Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Visibility="{Binding Direction, Converter={StaticResource ShowDown}}"
        Fill="Red" Data="{StaticResource DownArrow}"/>

As an example the code that controls whether the Up arrow is visible looks like:

 public class UpDirectionConverter : IValueConverter
    {
  
        #region IValueConverter Members
  
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            
            bool direction = (bool)value;
            if (direction == true)
                 return Visibility.Visible;
            return Visibility.Collapsed;
        }

The plus button will control the animation to hide/display quote information which I will describe later.Notice the Grid that is labeled MoreGrid initially has a height (target of the animation) of 0 so all the contained textBoxes will initially be hidden (they will be still be databound).

Now we will look at the Animations but I want to say that I could have displayed this information in the DetailPage but wanted to show that animations work well on the phone although not so smoothly in the emulator.. As the user touches the More button we are only as passed the button in the click handler and then must find the MoreGrid by running the Button’s parent (StackPanel) VisualTree to find the MoreGrid.

 private void MoreButton_Click(object sender, RoutedEventArgs e)
 {
     Button but = sender as Button;
     //get the StackPanel parent as it will contain the More grid whose Height we will animate
     DependencyObject container = GetParent(but, "QuoteContainer", true);
     more = FindVisualChildByName<Grid>(container, "MoreGrid");
 }

GetParent is a recursive method that will find the MoreButton’s container panel which is QuoteContainer

 public static DependencyObject GetParent(DependencyObject depObject, string name)
 {
     FrameworkElement parent = VisualTreeHelper.GetParent(depObject) as FrameworkElement;
     if (parent != null)
     {
         if (parent.Name == name)
           return parent;
         return GetParent(parent, name);
     }
     return null;
 }

Now that we have the QuoteContainer we can use  FindVisualChildByName to get  MoreGrid which is also a child of QuoteContainer. the code  looks like:

 public T FindVisualChildByName<T>(DependencyObject parent, string name) where T : DependencyObject
 {
     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
     {
         var child = VisualTreeHelper.GetChild(parent, i);
        string controlName = child.GetValue(Control.NameProperty) as string;
         if (controlName == name)
            return child as T;
         else
        {
            T result = FindVisualChildByName<T>(child, name);
            if (result != null)
               return result;
        }
     }
     return null;
 }

Silverlight progamming is often in exercise in running the visual tree that represents the UX and in this case when we find the desired MoreGrid we then fire either the expansion animation or hidding animation.

Now we add the code to the MoreButton_Click handler that will run the correct animation depending on the height of more so the finished method looks like:

 private void MoreButton_Click(object sender, RoutedEventArgs e)
        {
            Button but = sender as Button;
            //get the StackPanel parent as it will contain the More grid whose Height we will animate
            DependencyObject container = GetParent(but, "QuoteContainer", true);
            more = FindVisualChildByName<Grid>(container, "MoreGrid");
            if (more.Height == 0)
            {
  
                 Storyboard.SetTarget(OpenQuoteHeightAnimation, more);
                 but.Content = "-";
                 OpenUpStoryBoard.Begin();
            }
            else
            {
   
                but.Content = "+";
                 Storyboard.SetTarget(CloseQuoteHeightAnimation, more);
                 CloseStoryBoard.Begin();
            }
   
        }

The added code will also change the Button to + or – depending on the state. The animations were added as resources:

 <Storyboard x:Name="OpenUpStoryBoard" SpeedRatio="2" Completed="Storyboard_Completed">
           <DoubleAnimation x:Name="OpenQuoteHeightAnimation" 
                            Storyboard.TargetProperty="Height" 
                            From="0" To="90" />
  
 </Storyboard>
 <Storyboard x:Name="CloseStoryBoard" SpeedRatio="2" Completed="Storyboard_Completed">
           <DoubleAnimation x:Name="CloseQuoteHeightAnimation" 
                            Storyboard.TargetProperty="Height" 
                            From="30" To="0" />
   
 </Storyboard>

These are pretty simple as you can see we are just varying the Height property of the More Grid.

So now we have a potentially interesting UX but we are missing the Data and this is where I will add some complexity and is the  subject of Part 3.


Subscribe

Comments

No comments

Add Comment

Login to comment:
  *      *       

From this series