Design Parameter Storage and Retrieval
Naturally you want every project to improve on any previous version so in this case we decided to add a feature which allows a user to save the parameters for a given design and then later to retrieve that design. Of course, the repository for these design parameters is a SQL Server database.
The database design to store the information required to permit a user to retrieve a stored imprint design is relatively simple. All that was needed was a single table which contained each of the various design parameters (product color, imprint color, font family, etc.)
 | |
| Figure 5. SQL Server Table for Storing Design Parameters |
Silverlight 2 Code for Popup Control
<!-- Popup to display stored links -->
<Popup x:Name="popDisplayStoredLinks">
<Grid x:Name="grdDisplayStoredLinks" Background="#007799aa">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border BorderBrush="Black" BorderThickness="2" Background="WhiteSmoke"
CornerRadius="15" Grid.Column="1"
Grid.Row="1">
<StackPanel
Margin="8" Width="330" >
<StackPanel
Orientation="Vertical">
<TextBlock
Margin="5,5,0,5"
HorizontalAlignment="Center"
FontFamily="Comic Sans MS"
FontSize="22" >
Saved Designs for </TextBlock>
<TextBlock
x:Name="txbDisplayStoredLinksUserID"
Margin="0,0,5,5"
HorizontalAlignment="Center"
FontFamily="Comic Sans MS"
FontSize="22"
Text="UserIDHere" />
</StackPanel>
<ListBox x:Name="lstSavedDesigns" SelectionChanged
="lstSavedDesigns_SelectionChanged"
MouseLeftButtonUp="lstSavedDesigns_MouseLeftButtonUp"
Margin="10" />
<Button
x:Name="btnPopCancelDisplayStoredLinks"
Click="btnPopCancelDisplayStoredLinks_Click"
Margin="5"
Content="Cancel" Width="100"
HorizontalAlignment="Center" VerticalAlignment="Bottom" />
</StackPanel>
</Border>
</Grid>
</Popup> }
//This popup window is triggered
by setting its IsOpen property to true
void webService_GetDesignsByUserIdCompleted(object
sender, CustomerDesignsServiceReference.GetDesigns
ByUserIdCompletedEventArgs e)
{
if (_dbOperationsStatus[e.UserState.ToString()] ==
_dbOperationStatus.Canceling)
{
_dbOperationsStatus[e.UserState.ToString()] =
_dbOperationStatus.Canceled;
}
else
{
try
{
RetrievalCircleAnimation.Stop();
brdWaitAnimationRetrieveStoredLinks.Opacity = 0;
m_dtDatabaseRetrievalTimeout.Stop();
//Check to see how many results have
been returned
//If no results, display an error message
in the existing form
if (e.Result.Length < 1)
{
_dbOperationsStatus[e.UserState.ToString()] =
_dbOperationStatus.Selected;
txbRetrieveStoredLinksResults.Text = "No artwork
found for UserID "
+ txtRetrievalUserID.Text;
btnRetrieveStoredLinksMaskClose.Content = "Close";
return;
}
//If there is only one result, just display the
saved design immediately
else if (e.Result.Length == 1)
{
_dbOperationsStatus[e.UserState.ToString()] =
_dbOperationStatus.Selected;
RetrieveStoredLinksMask.Visibility = Visibility.Collapsed;
popRetrieveStoredLinks.IsOpen = false;
m_cdSavedDesigns = e.Result.ToList();
DisplaySavedDesign(0);
}
else if (e.Result.Length > 1)
{
_dbOperationsStatus[e.UserState.ToString()] =
_dbOperationStatus.Selected;
//If there are multiple results, save each record to a
CustomerDesign object and put a link in the
Display Stored Links popup
RetrieveStoredLinksMask.Visibility = Visibility.Collapsed;
m_cdSavedDesigns = e.Result.ToList();
lstSavedDesigns.ItemsSource = m_cdSavedDesigns;
lstSavedDesigns.DisplayMemberPath = "DesignName";
popRetrieveStoredLinks.IsOpen = false;
popDisplayStoredLinks.VerticalOffset =
(MainImageViewer.ActualHeight / 2)
- (174 / 2) + HeaderImage.ActualHeight - 25;
popDisplayStoredLinks.HorizontalOffset =
(HeaderImage.ActualWidth / 2)
- (350 / 2);
popDisplayStoredLinks.IsOpen = true;
txbDisplayStoredLinksUserID.Text = e.Result[0].UserID.ToString();
}
}
catch (System.Exception ex)
{
_dbOperationsStatus[e.UserState.ToString()] = _dbOperationStatus.Failed;
txbRetrieveStoredLinksResults.Text = "An Error occurred while
retrieving your artwork. Please try again.";
btnRetrieveStoredLinksMaskClose.Content = "Close";
btnRetrieveStoredLinksMaskClose.Focus();
Console.WriteLine(ex.Message);
}
}
Wait Animation
Since the process of communicating with a database located on a remote server is subject to the vagaries of the Internet, we decided to build a wait animation to request a user's patience while data is being saved or retrieved. A popular design these days for wait animations involves a series of circles themselves arranged in a circle. Each participating circle changes either its color or opacity in sequence with its partners, giving the effect of a Ferris wheel spinning around.
 | |
| Figure 7. |
Silverlight 2 Wait Animation
<!-- Wait Animation -->
<Grid
x:Name="RetrieveStoredLinksMask" Visibility="Collapsed" >
<Rectangle
Fill="Black" Opacity=".7" RadiusX="13" RadiusY="13"/>
<StackPanel >
<Border x:Name="brdWaitAnimationRetrieveStoredLinks"
BorderThickness="0"
BorderBrush="#FF000000"
Margin="0,40,0,20"
Height="64"
Width="64" >
<Border.Background>
<LinearGradientBrush
EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop
Color="#FF7A7777"/>
<GradientStop
Color="#FF181717" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid
ShowGridLines>="False" >
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="Auto" />
<ColumnDefinition
Width="Auto"/>
<ColumnDefinition />
<ColumnDefinition
Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition
Height="Auto" />
<RowDefinition
Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Ellipse x:Name
="waitAnimationCircle1" Grid.Row
="3" Grid.Column="1"
Grid.ColumnSpan="2"
Margin="0,-10,0,0"
Height="16" Width="16" Fill="White" />
<Ellipse x:Name="waitAnimationCircle2"
Grid.Row="1"
Grid.Column="0" Margin="6,2,0,0"
Height="16"
Width="16" Fill="#FFA7A6A6" />
<Ellipse x:Name="waitAnimationCircle3"
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="0,0,0,-10" Height="16"
Width="16" Fill="#FFA7A6A6" />
<Ellipse x:Name
="waitAnimationCircle4"
Grid.Row="1"
Grid.Column="3"
Margin="0,0,6,0"
Height="16"
Width="16" Fill="#FFA7A6A6" />
<Ellipse x:Name
="waitAnimationCircle5"
Grid.Row="2"
Grid.Column="3"
Margin="0,0,6,0"
Height="16"
Width="16" Fill="#FFA7A6A6" />
<
Ellipse x:Name
="waitAnimationCircle6" Grid.Row="2"
Grid.Column="0"
Margin="6,2,0,0"
Height="16"
Width="16" Fill="#FFA7A6A6" />
</Grid>
</Border>
<Border
Background="White"
CornerRadius="5"
Margin="20" >
<TextBlock
x:Name="txbRetrieveStoredLinksResults"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Text=""
Foreground="Black"
TextAlignment="Center" />
</Border>
<Button x:Name="btnRetrieveStoredLinksMaskClose" Click
="btnRetrieveStoredLinksMaskClose_Click"
HorizontalAlignment="Center" Margin="20"
Width="100" Content="Cancel"></ Button>
</StackPanel>
</Grid><!
--End of Wait Animation -->
//This wait animation can be started by calling its Begin() method
and later stopped by calling its Stop() method.
RetrievalCircleAnimation.Begin();
...
RetrievalCircleAnimation.Stop();
Building WPF/Silverlight animations is the forte of Expression Blend. In this case, the animation uses keyframes which change the color of the little circles to create the spinning effect. A useful technique for building an animation which will be incorporated into a much larger project is to create a separate Silverlight project with Blend and then once the animation has been refined, to transfer it into the main project.
 | |
| Figure 8. Expression Blend Timeline for Wait Animation |
Expression Blend Animation to Retrieve Designs Popup
<!-- Wait Animation for Retrieve Designs Popup -->
<Storyboard x:Name
="RetrievalCircleAnimation"
RepeatBehavior="Forever"
SpeedRatio=".25">
<ColorAnimationUsingKeyFrames
Storyboard.TargetName
="waitAnimationCircle6"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)" BeginTime="00:00:00">
<SplineColorKeyFrame KeyTime="00:00:00.1000000" Value="#FFFFFFFF"/>
<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFA7A6A6"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="waitAnimationCircle1"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)" BeginTime="00:00:00">
<SplineColorKeyFrame KeyTime="00:00:00.1000000" Value="#FFA7A6A6"/>
<SplineColorKeyFrame KeyTime="00:00:00.6000000" Value="#FFFFFFFF"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="waitAnimationCircle2"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)" BeginTime="00:00:00">
<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFFFFFFF"/>
<SplineColorKeyFrame KeyTime="00:00:00.3000000" Value="#FFA7A6A6"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="waitAnimationCircle3"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)" BeginTime="00:00:00">
<SplineColorKeyFrame KeyTime="00:00:00.3000000" Value="#FFFFFFFF"/>
< SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFA7A6A6"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="waitAnimationCircle4"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)" BeginTime="00:00:00">
<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFFFFFFF"/>
<SplineColorKeyFrame KeyTime="00:00:00.5000000" Value="#FFA7A6A6"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="waitAnimationCircle5"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)" BeginTime="00:00:00">
<SplineColorKeyFrame KeyTime="00:00:00.5000000" Value="#FFFFFFFF"/>
<SplineColorKeyFrame KeyTime="00:00:00.6000000" Value="#FFA7A6A6"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>