Estimated Time 45 Minutes
Silverlight started off as a browser plug-in. Since then, Silverlight has emerged as a client platform technology that not only includes browser based applications, but is now a desktop platform as well. This lab is designed to guide Winforms or desktop developers through the process of developing a desktop application in Silverlight.
In the lab you'll create a Silverlight web browser. It will truly be a desktop application. Along the way you'll learn how to enable Silverlight out-of-browser, detect the context the application is running in, customize the window, and how to interact with Microsoft Excel.
You'll start by using an existing application and enabling the out-of-browser feature. Next, you’ll determine if the application is running on the desktop or in the browser. You’ll then customize the look of the application. Finally you’ll learn how to interact with Microsoft Excel. The Silverlight application that you'll create is shown next:
Notice you can see HTML, Flash, and Silverlight running inside the app!
Since there are many features that aren’t available in browser, such as the WebBrowser control, you will need to be able to detect which context, desktop or browser, the application is currently running under. This exercise shows how to detect if your application is installed, displays a custom prompt asking the user to install you app, and finally how to install from a Button.
public partial class InstallPrompt : UserControl
{
public InstallPrompt()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(InstallPrompt_Loaded);
}
void InstallPrompt_Loaded(object sender, RoutedEventArgs e)
{
if (Application.Current.InstallState == InstallState.Installed)
{
InstallPanel.Visibility = Visibility.Collapsed;
AlreadyInstalledPanel.Visibility = Visibility.Visible;
}
else
{
InstallPanel.Visibility = Visibility.Visible;
AlreadyInstalledPanel.Visibility = Visibility.Collapsed;
}
}
}
Partial Public Class InstallPrompt
Inherits UserControl
Public Sub New()
InitializeComponent()
AddHandler Loaded, AddressOf InstallPrompt_Loaded
AddHandler InstallButton.Click, AddressOf InstallButton_Click
End Sub
Private Sub InstallPrompt_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
If Application.Current.InstallState = InstallState.Installed Then
InstallPanel.Visibility = Visibility.Collapsed
AlreadyInstalledPanel.Visibility = Visibility.Visible
Else
InstallPanel.Visibility = Visibility.Visible
AlreadyInstalledPanel.Visibility = Visibility.Collapsed
End If
End Sub
End Class
private void InstallButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.Install();
}
Private Sub InstallButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Application.Current.Install()
End Sub
Now that we have the InstallPrompt.xaml.cs or InstallPrompt.xaml.vb checking whether or not to prompt the user to install the application and installing if not currently installed, let’s turn our attention to detecting what context the application is running in. What we want is if the application is in a web browser we want to show the InstallPrompt screen, otherwise we should show the MainPage. The way we’re going to do it is by changing the RootVisual based on if the Application is running out of the Browser.
private void Application_Startup(object sender, StartupEventArgs e)
{
if (Application.Current.IsRunningOutOfBrowser)
{
this.RootVisual = new MainPage();
}
else
{
this.RootVisual = new InstallPrompt();
}
}
Private Sub Application_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
If Application.Current.IsRunningOutOfBrowser Then
Me.RootVisual = New MainPage()
Else
Me.RootVisual = New InstallPrompt()
End If
End Sub
Silverlight out of Browser enables you to ask the user to install your application with Elevated Privileges (EP). By running Silverlight in an EP mode you have a number of power pieces of functionality at your fingertips: Clipboard access, relaxed cross domain, direct access to the user folder, COM interop, and custom chrome. This exercise covers how to enable Elevated Privileges and then how to create a custom Chrome (a feature that’s crucial for kiosks or brand driving applications).
<StackPanel x:Name="WindowControlsPanel" Grid.Column="1" HorizontalAlignment="Right" Margin="0,2,4,0" Orientation="Horizontal" VerticalAlignment="Top">
<Button x:Name="OnTopButton" Margin="0,0,1,0" Style="{StaticResource
TopButtonStyle}" Width="16" Height="16" ToolTipService.ToolTip="Pin to the topmost window">
<Path Data="F1 M477.23441,395.96191 L473.29312,399.9386 L463.59912,
392.70959 L466.6774,389.59689 C467.56339,388.7099467.67639,387.38589
466.93039,386.63989C466.18439,385.89389464.86139,386.0069463.9744,
386.89389 L450.7294,400.13989C449.84241,401.02591 449.7294,402.34891
450.4754,403.09491C451.22141,403.84091 452.54639,403.72791453.4314,
402.8429L455.93942,400.3111 L463.16742,410.00711 L459.79639,413.3999
C458.9104,414.28589 458.79639,415.60791 459.5434,416.35489C460.29041,
417.10089 461.6134,416.98691 462.49939,416.10089L469.23541,409.36591
L480.4234,420.55591 C481.17041,421.2999482.49341,421.18689483.3804,
420.30191 C484.26541,419.41489484.37939,418.09091 483.63339,417.34491
L472.4444,406.15689L479.9364,398.66489 C480.82339,397.77789 480.9364,
396.45389480.18939,395.70789 C479.4444,394.96191 478.1214,395.07489
477.23441,395.96191"Fill="White"Stretch="Fill"UseLayoutRounding="False"
d:LayoutOverrides="GridBox" RenderTransformOrigin="0.5,0.5"
Margin="1,0,1,2">
<Path.RenderTransform>
<CompositeTransform Rotation="45" TranslateY="1.8068817553285044E-09"/>
</Path.RenderTransform>
</Path>
</Button>
<Button x:Name="MinimizeButton" Width="16" Height="16" Margin="0,0,1,0"
Style="{StaticResource TopButtonStyle}" ToolTipService.ToolTip="Minimize" Padding="0">
<Path Data="F1M229.417,216.229L208.354,237.292C207.544,238.103,207.544,239.416,208.3
54,240.227C209.165,241.037,210.479,241.037,211.289,240.227L232.352,
219.165C233.162,218.354,233.162,217.04,232.352,216.229C231.541,215.419,
230.227,215.419,229.417,216.229"Fill="White" Stretch="Fill"
UseLayoutRounding="False" RenderTransformOrigin="0.5,0.5" Height="6"
Width="6" Margin="0,6,0,0">
<Path.RenderTransform>
<CompositeTransform Rotation="45"/>
</Path.RenderTransform>
</Path>
</Button>
<Button x:Name="MaximizeButton" Width="16" Height="16" Margin="0,0,1,0"
Style="{StaticResource TopButtonStyle}"ToolTipService.ToolTip="Maximize">
<Path Data="F1M74.313,328.7861C74.313,329.5261,73.713,330.1281,72.973,330.1281L53.03
3,330.1281C52.292,330.1281,51.692,329.5261,51.692,328.7861L51.692,
308.4751C51.692,307.7351,52.292,307.1361,53.033,307.1361L72.973,
307.1361C73.713,307.1361, 74.313,307.7351,74.313,308.4751zM74.806,
305.0221L51.199,305.0221C50.323,305.0221,49.612,305.7311,49.612,
306.6081L49.612,330.6551C49.612,331.5321,50.323,332.2411,51.199,
332.2411L74.806,332.2411C75.683,332.2411,76.393,331.5321,
76.393,330.6551L76.393,306.6081C76.393,305.7311,75.683,305.0221,
74.806,305.0221" Fill="White" Stretch="Fill"UseLayoutRounding="False"/>
</Button>
<Button x:Name="CloseButton" Width="16" Height="16" Margin="0" Style="{StaticResource TopButtonStyle}" ToolTipService.ToolTip="Close">
<Path Data="M0.54881889,0 C0.68929577,0 0.82977271,0.053546324
0.93699646,0.16063902 L3.3335769,2.5573325 L5.730268,0.1606418
C5.9444532,0.053543516 6.2919092,-0.053543516 6.506361,0.1606418
C6.7205462,0.37508935 6.7205462,0.72254932 6.506361,0.93699688
L4.1097264,3.3335183 L6.5063634,5.730268 C6.7205486,5.9444532
6.7205486,6.291913 6.5063634,6.5063605 C6.2919116,6.7205458
5.9447179,6.7205458 5.7302704,6.5063605 L3.3335588,4.1096492
L0.93673187,6.5063634 C0.72254658,6.7205486 0.37508655,6.7205486
0.16063894,6.5063634 C-0.053546317,6.2919121 -0.053546317,5.9447184
0.16063894,5.7302704 L2.5574095,3.3334999 L0.16064122,0.93673182 C
0.053544026,0.72254652 –0.053544026,0.3750906 0.16064122,0.16063902
C0.26786506,0.053546324 0.40834194,0 0.54881889,0 z" Fill="White"
Stretch="Fill" UseLayoutRounding="False" Margin="2" />
</Button>
</StackPanel>
public MainPage()
{
InitializeComponent();
// Register Click events for the buttons in the WindowControlsPanel
this.OnTopButton.Click += new RoutedEventHandler(OnTopButton_Click);
this.MinimizeButton.Click += new RoutedEventHandler(MinimizeButton_Click);
this.MaximizeButton.Click += new RoutedEventHandler(MaximizeButton_Click);
this.CloseButton.Click += new RoutedEventHandler(CloseButton_Click);
}
//Pin to Top – Setting the value of Application.Current.MainWindow.TopMost enables
//you to pin your application on top of every other app.
void OnTopButton_Click(object sender, RoutedEventArgs e)
{
// Toggle between being on top and not
Application.Current.MainWindow.TopMost = !Application.Current.MainWindow.TopMost;
}
//Minimize – To minimize an out of browser application set the value of
//Application.Current.MainWindow.WindowState to WindowState.Minimized.
void MinimizeButton_Click(object sender, RoutedEventArgs e)
{
// Minimize the application
Application.Current.MainWindow.WindowState = WindowState.Minimized;
}
//Maximize– To maximize the window, set the value of
//Application.Current.MainWindow.WindowState to WindowState.Maximized. In this event
//handler we’re toggling between the Normal WindowState and Maximized.
void MaximizeButton_Click(object sender, RoutedEventArgs e)
{
// Toggle between the Normal and Maximized state
if (Application.Current.MainWindow.WindowState != WindowState.Maximized)
{
Application.Current.MainWindow.WindowState = WindowState.Maximized;
}
else
{
Application.Current.MainWindow.WindowState = WindowState.Normal;
}
}
//Close – To close, simply call the Close method of Application.Current.MainWindow.
void CloseButton_Click(object sender, RoutedEventArgs e)
{
// Close the application
Application.Current.MainWindow.Close();
}
Partial Public Class MainPage
Inherits UserControl
Public Sub New()
InitializeComponent()
' Register Click events for the buttons in the WindowControlsPanel
AddHandler OnTopButton.Click, AddressOf OnTopButton_Click
AddHandler MinimizeButton.Click, AddressOf MinimizeButton_Click
AddHandler MaximizeButton.Click, AddressOf MaximizeButton_Click
AddHandler CloseButton.Click, AddressOf CloseButton_Click
End Sub
Private Sub OnTopButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Toggle between being on top and not
Application.Current.MainWindow.TopMost = Not Application.Current.MainWindow.TopMost
End Sub
Private Sub MinimizeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Minimize the application
Application.Current.MainWindow.WindowState = WindowState.Minimized
End Sub
Private Sub MaximizeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Toggle between the Normal and Maximized state
If Application.Current.MainWindow.WindowState <> WindowState.Maximized Then
Application.Current.MainWindow.WindowState = WindowState.Maximized
Else
Application.Current.MainWindow.WindowState = WindowState.Normal
End If
End Sub
Private Sub CloseButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)' Close the application
Application.Current.MainWindow.Close()
End Sub
End Class
As mentioned above, enabling Elevated Privileges opens up a world of possibilities. One feature is the AutomationFactory. This enables you to call COM components from Silverlight. In our application we are going to enable the user to export their Bookmarks into Excel, Word, or e-mail them with Outlook.
<Border x:Name="ExportPanel" BorderThickness="0,2,0,0" BorderBrush="#FF666666" Margin="0,2,0,0" Grid.Row="1" Height="57" >
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFDADADA"/>
<GradientStop Color="#FFA5A5A5" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid HorizontalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="EXPORT BOOKMARKS TO" d:LayoutOverrides="Height" Foreground="#FF181818" HorizontalAlignment="Center" Margin="2,2,0,0" TextOptions.TextHintingMode="Animated" VerticalAlignment="Top" />
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" VerticalAlignment="Bottom" Height="35" Margin="2,0,0,2">
<Button x:Name="ExcelButton" Margin="0,0,5,0">
<Image Source="Images/Excel.png" Stretch="Fill"/>
</Button>
<Button x:Name="WordButton" Margin="0,0,5,0">
<Image Source="Images/Word.png" Stretch="Fill"/>
</Button>
<Button x:Name="OutlookButton" Margin="0,0,5,0">
<Image Source="Images/Outlook.png" Stretch="Fill"/>
</Button>
<Button x:Name="PowerPointButton" Margin="0">
<Image Source="Images/notepad.png" Stretch="Fill"/>
</Button>
</StackPanel>
</Grid>
</Border>
// Register Click events for the Export buttons this.ExcelButton.Click += new RoutedEventHandler(ExcelButton_Click); this.WordButton.Click += new RoutedEventHandler(WordButton_Click); this.OutlookButton.Click += new RoutedEventHandler(OutlookButton_Click); this.PowerPointButton.Click += new RoutedEventHandler(PowerPointButton_Click);
'Register Click events for the Export buttons AddHandler ExcelButton.Click, AddressOf ExcelButton_Click AddHandler WordButton.Click, AddressOf WordButton_Click AddHandler OutlookButton.Click, AddressOf OutlookButton_Click AddHandler PowerPointButton.Click, AddressOf PowerPointButton_Click
void ExcelButton_Click(object sender, RoutedEventArgs e)
{
dynamic excel = AutomationFactory.CreateObject("Excel.Application");
excel.Visible = true;
dynamic workbook = excel.workbooks;
workbook.Add();
dynamic sheet = excel.ActiveSheet;
dynamic cell = null;
int i = 1;
// Populate the excel sheet
foreach (var item in (LayoutRoot.DataContext as Bookmarks).Sites)
{
cell = sheet.Cells[i, 1];
cell.Value = item.Title;
cell = sheet.Cells[i, 2];
cell.Value = item.Uri;
cell.ColumnWidth = 100;
i++;
}
}
Private Sub ExcelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim excel As Object = AutomationFactory.CreateObject("Excel.Application")
excel.Visible = True
Dim workbook As Object = excel.workbooks
workbook.Add()
Dim sheet As Object = excel.ActiveSheet
Dim cell As Object = Nothing
Dim i As Integer = 1
' Populate the excel sheet
For Each item In (TryCast(LayoutRoot.DataContext, Bookmarks)).Sites cell = sheet.Cells(i, 1)
cell.Value = item.Title
cell = sheet.Cells(i, 2)
cell.Value = item.Uri
cell.ColumnWidth = 100
i += 1
Next item
End Sub
void WordButton_Click(object sender, RoutedEventArgs e)
{
if (AutomationFactory.IsAvailable)
{
dynamic word = AutomationFactory.CreateObject("Word.Application");
word.Visible = true;
word.Documents.Add();
word.Selection.TypeText("Bookmarks");
word.Selection.TypeText(string.Format("Exported at: {0}", DateTime.Today.ToShortDateString()));
word.Selection.TypeParagraph();
foreach (var item in (LayoutRoot.DataContext as Bookmarks).Sites)
{
word.Selection.TypeText(string.Format("{0} \vURL: {1}\v", item.Title, item.Uri));
}
word.ActiveDocument.SaveAs("BookmarksFromSL");
}
}
Private Sub WordButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
If AutomationFactory.IsAvailable Then
Dim word As Object = AutomationFactory.CreateObject("Word.Application")
word.Visible = True
word.Documents.Add()
word.Selection.TypeText("Bookmarks")
word.Selection.TypeText(String.Format("Exported at: {0}",Date.Today.ToShortDateString()))
word.Selection.TypeParagraph()
For Each item In (TryCast(LayoutRoot.DataContext, Bookmarks)).Sites
word.Selection.TypeText(String.Format("{0} " & vbVerticalTab & "URL: {1}" & vbVerticalTab, item.Title, item.Uri))
Next item
word.ActiveDocument.SaveAs("BookmarksFromSL")
End If
End Sub
void OutlookButton_Click(object sender, RoutedEventArgs e)
{
if (AutomationFactory.IsAvailable)
{
dynamic outlook = AutomationFactory.CreateObject("Outlook.Application");
dynamic mail = outlook.CreateItem(0);
mail.To = "me@myname.com";
mail.Subject = "My Bookmarks";
StringBuilder sb = new StringBuilder();
foreach (var item in (LayoutRoot.DataContext as Bookmarks).Sites)
{
sb.Append(string.Format("{0} \vURL: {1}\v\v", item.Title, item.Uri));
}
mail.Body = sb.ToString();
mail.Display();
}
}
Private Sub OutlookButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
If AutomationFactory.IsAvailable Then
Dim outlook As Object = AutomationFactory.CreateObject("Outlook.Application")
Dim mail As Object = outlook.CreateItem(0)
mail.To = "me@myname.com"
mail.Subject = "My Bookmarks"
Dim sb As New StringBuilder()
For Each item In (TryCast(LayoutRoot.DataContext, Bookmarks)).Sites
sb.Append(String.Format("{0} " & vbVerticalTab & "URL: {1}" & vbVerticalTab & vbVerticalTab, item.Title, item.Uri))
Next item
mail.Body = sb.ToString()
mail.Display()
End If
End Sub
void PowerPointButton_Click(object sender, RoutedEventArgs e)
{
if (AutomationFactory.IsAvailable)
{
dynamic cmd = AutomationFactory.CreateObject("WScript.Shell");
cmd.Run(@"c:\windows\notepad.exe", 1, true);
}
}
Private Sub PowerPointButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
If AutomationFactory.IsAvailable Then
Dim cmd As Object = AutomationFactory.CreateObject("WScript.Shell")
cmd.Run("c:\windows\notepad.exe", 1, True)
End If
End Sub
In this exercise you examined how to create a Silverlight project for the desktop. Additionally you explored many aspects of the out-of-browser feature and satisfied the following requirements:
This application demonstrated some of the more basic features of out-of-browser. In other labs you will take a closer look at the more advanced features.
Comments (0)