Sunday, August 8, 2010

Pass Parameters from ASP.NET to Silverlight

It is very straight forward to pass parameters from an asp.net page to a silverlight application. In my case, I had an asp.net application and wanted to integrate silverlight in one of my pages. I needed to pass some values such as ID and user role. Let's look at some code. First, I created a class, in my Silverlight application, to encapsulate my values. The constructor of my class takes in an IDictionary.

public class Dashboard
{
private string _ParishId;
private bool _IsReadOnly;
private bool _IsGSTSOrSuperParish;
internal Dashboard(IDictionary<string, string> parameters)
{
_ParishId = parameters["pid"];
_IsReadOnly = Convert.ToBoolean(parameters["iro"]);
_IsGSTSOrSuperParish = Convert.ToBoolean(parameters["igs"]);
}
public string ParishId
{
get { return _ParishId; }
}
public bool IsReadOnly
{
get { return _IsReadOnly; }
}
public bool IsGSTSOrSuperParish
{
get { return _IsGSTSOrSuperParish; }
}
}

Now, in the App.xaml application start up event i new up an instance of the class i created passing in the initParams of the StartupEventArgs.
Below is the markup needed for this.

private void Application_Startup(object sender, StartupEventArgs e)
{
Dashboard db = new Dashboard(e.InitParams);
this.RootVisual = new MainPage(db.ParishId,db.IsReadOnly,db.IsGSTSOrSuperParish);
}

Now that i have things set up for the mainPage.xaml, all i have to do is get those values on mainPage. And that's it on the silverlight side. I still have to set up how to get the actual values from ASP.NET. Below is the code for the mainPage.xaml.

public partial class MainPage : UserControl
{
private string _id;
private bool _IsReadOnly;
private bool _IsGSTSOrSuperParish;
public MainPage(string id, bool isReadOnly, bool isGSTSOrSuperParish)
{
InitializeComponent();
_id = id;
_IsReadOnly = isReadOnly;
_IsGSTSOrSuperParish = isGSTSOrSuperParish;
Loaded += new RoutedEventHandler(Page_Loaded);
}
...

Finally, I added a parameter (to the asp.net user control where my silverlight reference is) and called it initParam and gave it an ID of 'prm' so I can use it in code behind of this user control. First, let's take a look at the HTML.

<div id="silverlightControlHost">
<object id="tempSil" data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="../ClientBin/DB.Silverlight.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="4.0.50401.0" />
<param name="autoUpgrade" value="true" />
<param name="initParams" runat="server" id="prm" />
<param name="windowless" value="true" />
 
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>

And here is the code behind and is pretty straight forward..just passing in values.

public partial class UserControls_VE_db : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
using (var proxy = new CapitalAreaService.ServiceClient())
{
this.prm.Attributes["value"] = string.Format("pid={0},iro={1},igs={2}", 
proxy.GetParishId(SystemRole.GetParisAbbreviation()),SystemRole.IsReadOnly(),
SystemRole.IsGSTSOrSuperParish());
}
}
}

That's all it take to pass values from ASP.NET to Silverlight as needed.

Saturday, August 7, 2010

Silverlight Form Flip Animation

In my recent project I had a datagrid and needed to have a search option where the user can do a basic search or an advanced search, so I thought about implementing this using a form flip animation. Basic search on one side and advanced search on the other. This saved me space and all i had to do is add a search button above the grid and upon click pop up the search form. Below is a screen shots of what this looks like.



When the user clicks the search icon on the first screen shot, it pops up the basic search form and upon clicking Advanced search the form flips and shows the advanced search form. Now, let's look at some code.

First I am going to add a stack panel for the search icon then right underneath that I am addding a popup control in mainpage.xaml.

<StackPanel Orientation="Horizontal">
<Button Height="23"  
HorizontalAlignment="Left"   
Name="btnLaunchSearch" VerticalAlignment="Top"  
Click="btnLaunchSearch_Click">
<Button.Content>
<Image Source="./images/search.jpg"   ToolTipService.ToolTip="Search" />
</Button.Content>
</Button>
</StackPanel>
<Popup x:Name="SearchFormPopup" VerticalOffset="100" HorizontalOffset="100">
</Popup>
Now, I am going to add a view for the search form. I created a folder called UserControls then added a Search.xaml user control. I put the styles in a separate file - used a resource dictionary.

<UserControl x:Class="DB.Silverlight.UserControls.Search"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="500">
<UserControl.Resources>
<ResourceDictionary x:Key="SD">
<ResourceDictionary.MergedDictionaries >
<ResourceDictionary  Source="../Dictionaries/SearchDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary> 
<Storyboard x:Name="StartingPosition">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="FormBack"
Storyboard.TargetProperty="(UIElement.RenderTransform).TransformGroup.Children[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="5000" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="AdvancedSearch">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="PanelProjection"
Storyboard.TargetProperty="RotationY">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="0" />
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="90" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="FormFront"
Storyboard.TargetProperty="(UIElement.RenderTransform).TransformGroup.Children[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="0" />
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="0" />
<SplineDoubleKeyFrame KeyTime="00:00:01.01"
Value="5000" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="FormBack"
Storyboard.TargetProperty="(UIElement.RenderTransform).TransformGroup.Children[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="5000" />
<SplineDoubleKeyFrame KeyTime="00:00:00.99"
Value="5000" />
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="BackPanelProjection"
Storyboard.TargetProperty="RotationY">
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="270" />
<SplineDoubleKeyFrame KeyTime="00:00:02"
Value="360" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="BasicSearch">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="FormBack"
Storyboard.TargetProperty="(UIElement.RenderTransform).TransformGroup.Children[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="0" />
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="0" />
<SplineDoubleKeyFrame KeyTime="00:00:01.01"
Value="5000" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="BackPanelProjection"
Storyboard.TargetProperty="RotationY">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="0" />
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="-90" />
</DoubleAnimationUsingKeyFrames>
 
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="PanelProjection"
Storyboard.TargetProperty="RotationY">
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="-270" />
<SplineDoubleKeyFrame KeyTime="00:00:02"
Value="-360" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="FormFront"
Storyboard.TargetProperty="(UIElement.RenderTransform).TransformGroup.Children[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00"
Value="5000" />
<SplineDoubleKeyFrame KeyTime="00:00:00.99"
Value="5000" />
<SplineDoubleKeyFrame KeyTime="00:00:01"
Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Canvas>
<StackPanel x:Name="FormFront">
<StackPanel.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform />
</TransformGroup>
</StackPanel.RenderTransform>
<StackPanel.Projection>
<PlaneProjection x:Name="PanelProjection"
RotationX="0"
RotationY="0"
RotationZ="0" />
</StackPanel.Projection>
<Border Name="mainBorder" Style="{StaticResource ModalDialogBorder}" > 
<Grid x:Name="LayoutRoot" Width="399" Margin="10,10,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="70" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Grid.Row="0" >
<TextBlock Margin="20" Text="Note:Search by user's first name, last name, or by business name."></TextBlock>
</StackPanel>
<TextBox TabIndex="0" Name="txtSearch" Grid.Row="1" Height="30" Width="260" Margin="0,5,0,20"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Grid.Row="2" Margin="89,0,89,55">
<Button x:Name="SearchButton" Height="30" Width="100"  Content="Search"/>
<Button x:Name="CancelButton" Height="30" Width="100"  Content="Cancel"/>
</StackPanel>
<Button x:Name="Advanced"
Content="Advanced Search"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Width="Auto"
Background="DarkGreen"
FontFamily="Georgia"
FontSize="10"
Grid.Row="5"
Margin="10,0"
Grid.Column="0" />
</Grid>
</Border>
</StackPanel>
<StackPanel x:Name="FormBack">
<StackPanel.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform />
</TransformGroup>
</StackPanel.RenderTransform>
<StackPanel.Projection>
<PlaneProjection x:Name="BackPanelProjection"
RotationX="0"
RotationY="0"
RotationZ="0" />
</StackPanel.Projection>
<Border Style="{StaticResource ModalDialogBorder}" >
<Grid x:Name="theForm" Width="399">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Placard Type"
Grid.Row="0"
Grid.Column="0"
Style="{StaticResource Prompt}" />
<ComboBox  
Name="cbPlacardType"   
Grid.Row="0"
Grid.Column="1" 
Style="{StaticResource EntryDrop}" />
<TextBlock Text="Status"
Grid.Row="1"
Grid.Column="0"
Style="{StaticResource Prompt}" />
<ComboBox  
Name="cbStatus"   
Grid.Row="1"
Grid.Column="1" 
Style="{StaticResource EntryDrop}" />
<TextBlock Text="Date Entered"
Grid.Row="2"
Grid.Column="0"
Style="{StaticResource Prompt}" />
 
 
<TextBlock Text="From" Margin="8,0,231,0"
Grid.Row="2"
Grid.Column="1" Width="30" />  
<TextBox x:Name="txtFrom"
Grid.Row="2"
Grid.Column="1"
Width="80" Margin="37,0,162,0" />
<TextBlock Text="To" Width="30"
Grid.Row="2"
Grid.Column="1" Margin="116,0,123,0" />
<TextBox x:Name="txtTo"
Grid.Row="2"
Grid.Column="1"
Width="80" Margin="150,0,49,0" />
<TextBlock Text="Placard Id"
Grid.Row="3"
Grid.Column="0"
Style="{StaticResource Prompt}" />
<TextBox x:Name="txtPlacardId"
Grid.Row="3"
Grid.Column="1"
Style="{StaticResource Entry}"  />
<TextBlock Text="Business Name"
Grid.Row="4"
Grid.Column="0"
Style="{StaticResource Prompt}" />
<TextBox x:Name="txtBusinessName"
Grid.Row="4"
Grid.Column="1"
Style="{StaticResource Entry}" />
<TextBlock Text="Contact First Name"
Grid.Row="5"
Grid.Column="0"
Style="{StaticResource Prompt}" />
<TextBox x:Name="txtContactFirstName"
Grid.Row="5"
Grid.Column="1"
Style="{StaticResource Entry}" />
<TextBlock Text="Contact Last Name"
Grid.Row="6"
Grid.Column="0"
Style="{StaticResource Prompt}" />
<TextBox x:Name="txtContactLastName"
Grid.Row="6"
Grid.Column="1"
Style="{StaticResource Entry}" />
<Button x:Name="btnAdvancedSearch"
Content=" Search "
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Width="95"
Background="DarkGreen"
FontFamily="Georgia"
FontSize="12"
Grid.Row="7"
Margin="30,0,0,10" />
<Button x:Name="btnAdvancedSearchCancel"
Content=" Cancel "
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Width="95"
Background="DarkGreen"
FontFamily="Georgia"
FontSize="12"
Grid.Row="7"
Margin="10,10"
Grid.Column="1" />
<Button x:Name="Basic"
Content="Switch to Basic Search"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Width="112"
Background="DarkGreen"
FontFamily="Georgia"
FontSize="10"
Grid.Row="8"
Margin="0,0,12,5"
Grid.Column="1" />
</Grid>
</Border>
</StackPanel>
</Canvas>
</UserControl>

Now, in the code behind of the search form I added the mecanics to do the flip animation.

public partial class Search : UserControl
{
public Search()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Search_Loaded);
Advanced.Click += new RoutedEventHandler(Advanced_Click);
Basic.Click += new RoutedEventHandler(Basic_Click);
}
void Search_Loaded(object sender, RoutedEventArgs e)
{
StartingPosition.Begin();
//TODO: Load comboboxes..
}
void Advanced_Click(object sender, RoutedEventArgs e)
{
AdvancedSearch.Begin();
}
void Basic_Click(object sender, RoutedEventArgs e)
{
BasicSearch.Begin();
}
}

All i have left now is the code to handle the search button in mainpage.xaml and it's pretty simple - i just have to new up an instance of the popup control that i created in mainpage and also new up an instance of the search form user control and ofcourse code to handle my data. Since my data code involves WCF and is a bit lengthy I am just gonna leave that up to you to add your own data handling here. Below is the code needed in mainpage.

private void btnLaunchSearch_Click(object sender, RoutedEventArgs e)
{
SearchFormPopup = new Popup();
form = new Search();
form.CancelButton.Click += new RoutedEventHandler(CancelButton_Click);
form.SearchButton.Click += new RoutedEventHandler(SearchButton_Click);
form.btnAdvancedSearchCancel.Click += new RoutedEventHandler(CancelButton_Click);
form.btnAdvancedSearch.Click += new RoutedEventHandler(AdvancedSearchButton_Click);
SearchFormPopup.Child = form;
SearchFormPopup.IsOpen = true;
}
private void AdvancedSearchButton_Click(object sender, RoutedEventArgs e)
{
LoadFilterdDataboardDataAdvancedSearch();
SearchFormPopup.IsOpen = false;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
SearchFormPopup.IsOpen = false;
}
private void SearchButton_Click(object sender, RoutedEventArgs e)
{
LoadFilteredDashBoardDataSearch();
SearchFormPopup.IsOpen = false;
}

And that's it. If you have any comments or better ways to do this, let me know.