posts - 615, comments - 10492, trackbacks - 594, articles - 0
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[索引页]
[源码下载]


稳扎稳打Silverlight(44) - 4.0浏览器外运行(Out Of Browser)之OOB的增强及其新增的NotificationWindow



作者:webabcd


介绍
Silverlight 4.0 OOB 模式的新特性:

  • 新增了 Closing 事件
  • 实现程序在 OOB 模式下的自动更新
  • NotificationWindow - 在 OOB 模式下显示通知窗口,也就是 toast
  • 实现自定义的 NotificationWindow



在线DEMO
http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html


示例
1、OOB(Out Of Browser)模式的复习,以及其新增的 Closing 事件
Demo.xaml

代码
<navigation:Page x:Class="Silverlight40.OutOfBrowser.Demo" 
           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"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title
="Other Page">
    
<Grid x:Name="LayoutRoot">

        
<StackPanel HorizontalAlignment="Left">

            
<Button Name="btnOutOfBrowser" Margin="50" Click="btnOutOfBrowser_Click" />

            
<Button Name="btnClose" Margin="50" Content="关闭" Click="btnClose_Click" />

            
<TextBlock Text="OOB 模式下网络状况的检测,以及程序的升级详见本目录下的 AutoUpdateDemo.xaml" Margin="5" />

            
<TextBlock Text="OOB 模式的 toast(以及与 Popup 的对比)详见本目录下的 NotificationWindowDemo.xaml" Margin="5" />

            
<TextBlock Text="OOB 模式下自定义 NotificationWindow 的内容及样式详见本目录下的 CustomNotificationWindowDemo.xaml" Margin="5" />

        
</StackPanel>
        
    
</Grid>
</navigation:Page>


Demo.xaml.cs

代码
/*
 * Silverlight 3.0 时代具有如下特性
 * Application.InstallStateChanged - 浏览器外运行的相关状态发生改变时所触发的事件
 * Application.InstallState - 浏览器外运行的相关状态 [System.Windows.InstallState 枚举]
 *     NotInstalled - 在浏览器中运行
 *     Installing - 安装到桌面中
 *     Installed - 在浏览器外运行
 *     InstallFailed - 安装到桌面的过程中发生错误
 * Application.IsRunningOutOfBrowser - 当前程序是否是从浏览器外启动的
 * Application.Install() - 安装 Silverlight 程序到浏览器外(卸载只能通过右键菜单的方式卸载)
 * Application.CheckAndDownloadUpdateAsync, Application.CheckAndDownloadUpdateCompleted - 一对异步方法/事件,用于更新浏览器外运行的 Silverlight 程序(从服务器上下载新的版本)
 * 
 * 启用 OOB:在 Silverlight 项目上单击右键 -> 属性 -> Silverlight -> 选中 Enable running application out of the browser
 * 配置 OOB:在 Silverlight 项目上单击右键 -> 属性 -> Silverlight -> Out-of-Browser Settings 可以对“浏览器外运行”的相关参数做设置(也可以手动修改 Properties/OutOfBrowserSettings.xml)
 
*/


/*
 * 调试 OOB 模式下的 Silverlight 程序:启用 OOB 模式,将 Silverlight 项目设置为启动项目,然后运行即可
 
*/


/*
 * 本例用于演示 Closing 事件
 * Application.Current.MainWindow - OOB 模式下的应用程序窗口。属性值为 System.Windows.Window 类型
 * Window.Activate() - 激活窗口,使之具有焦点,并置于最前面
 * Window.IsActive - 是否为激活窗口(仅 get)
 * Window.Close() - 关闭窗口
 * Window.Closing - 窗口关闭前触发的事件。事件参数为 System.ComponentModel.ClosingEventArgs 类型
 *     ClosingEventArgs.IsCancelable - 是否可以取消窗口的关闭事件
 *     ClosingEventArgs.Cancel - 是否取消窗口的关闭事件
 
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

namespace Silverlight40.OutOfBrowser
{
    
public partial class Demo : Page
    {
        
public Demo()
        {
            InitializeComponent();
        }

        
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            
if (App.Current.IsRunningOutOfBrowser)
                btnOutOfBrowser.Content 
= "卸载";
            
else
                btnOutOfBrowser.Content 
= "安装";

            Init();
        }

        
private void btnOutOfBrowser_Click(object sender, RoutedEventArgs e)
        {
            
if (!App.Current.IsRunningOutOfBrowser && App.Current.InstallState == InstallState.NotInstalled)
                App.Current.Install();
            
else
                MessageBox.Show(
"已经安装,使用右键卸载");
        }

        
void Init()
        {
            
if (Application.Current.IsRunningOutOfBrowser)
                Application.Current.MainWindow.Closing 
+= new EventHandler<System.ComponentModel.ClosingEventArgs>(MainWindow_Closing);
        }

        
void MainWindow_Closing(object sender, System.ComponentModel.ClosingEventArgs e)
        {
            
if (MessageBox.Show("确认关闭吗?""确认", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {

            }
            
else
            {
                
if (e.IsCancelable)
                    e.Cancel 
= true;
            }
        }

        
private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            
if (Application.Current.IsRunningOutOfBrowser)
                Application.Current.MainWindow.Close();
        }
    }
}



2、演示如何实现程序在 OOB 模式下的自动更新
AutoUpdateDemo.xaml

代码
<navigation:Page x:Class="Silverlight40.OutOfBrowser.AutoUpdateDemo" 
           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"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title
="AutoUpdateDemo Page">
    
<Grid x:Name="LayoutRoot">
        
<StackPanel>
            
            
<Button Name="btnOutOfBrowser" Margin="50" Click="btnOutOfBrowser_Click" />
            
            
<TextBlock Name="lblMsg" />
            
        
</StackPanel>
    
</Grid>
</navigation:Page>


AutoUpdateDemo.xaml.cs

代码
/*
 * 本例演示 Silverlight 应用程序在 OOB 模式下的自动更新
 * 注1:Silverlight 应用程序根据 Assembly Version 来判断是否需要更新
 * 注2:程序下载成功后,需要重启 Silverlight 应用程序,这样运行的才是更新后的程序
 * 
 * NetworkInterface.GetIsNetworkAvailable() - 网络是否有效
 * NetworkChange.NetworkAddressChanged - 网络状态发生变化时所触发的事件
 * Application.CheckAndDownloadUpdateAsync, Application.CheckAndDownloadUpdateCompleted - 一对异步方法/事件,用于更新浏览器外运行的 Silverlight 程序(从服务器上下载新的版本)
 * CheckAndDownloadUpdateCompletedEventArgs.UpdateAvailable - 是否已经成功更新了版本
 * CheckAndDownloadUpdateCompletedEventArgs.Error - 下载更新时发生了异常
 
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

using System.Net.NetworkInformation;

namespace Silverlight40.OutOfBrowser
{
    
public partial class AutoUpdateDemo : Page
    {
        
public AutoUpdateDemo()
        {
            InitializeComponent();
        }

        
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            
if (App.Current.IsRunningOutOfBrowser)
                btnOutOfBrowser.Content 
= "卸载";
            
else
                btnOutOfBrowser.Content 
= "安装";
            
            Init();
        }

        
private void btnOutOfBrowser_Click(object sender, RoutedEventArgs e)
        {
            
if (!App.Current.IsRunningOutOfBrowser && App.Current.InstallState == InstallState.NotInstalled)
                App.Current.Install();
            
else
                MessageBox.Show(
"已经安装,使用右键卸载");
        }

        
private void Init()
        {
            lblMsg.Text 
= string.Format("网络状态:{0}", NetworkInterface.GetIsNetworkAvailable().ToString());

            
// 网络状态发生改变时所触发的事件,可以拔网线看效果
            NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);

            
if (App.Current.IsRunningOutOfBrowser && NetworkInterface.GetIsNetworkAvailable())
            {
                App.Current.CheckAndDownloadUpdateCompleted 
+= new CheckAndDownloadUpdateCompletedEventHandler(Current_CheckAndDownloadUpdateCompleted);
                App.Current.CheckAndDownloadUpdateAsync();

                lblMsg.Text 
+= "\n检查更新。。。";
            }
        }

        
void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
        {
            lblMsg.Text 
+= "\n";
            lblMsg.Text 
+= string.Format("网络状态:{0}", NetworkInterface.GetIsNetworkAvailable().ToString());
        }

        
void Current_CheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
        {
            
if (e.UpdateAvailable)
            {
                lblMsg.Text 
+= "\n更新完毕,请重启程序";
            }
            
else
            {
                
if (e.Error == null)
                    lblMsg.Text 
+= "\n程序无更新(如果有新更新要修改 Assembly Version)";
                
else
                    lblMsg.Text 
+= "\n" + e.Error.ToString();
            }
        }
    }
}



3、演示 NotificationWindow(toast) 的效果,以及其和 Popup 的对比
NotificationWindowDemo.xaml

代码
<navigation:Page x:Class="Silverlight40.OutOfBrowser.NotificationWindowDemo" 
           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"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title
="NotificationWindowDemo Page">
    
<Grid x:Name="LayoutRoot">
        
<StackPanel HorizontalAlignment="Left">
            
<Button Name="btnOutOfBrowser" Margin="50" Click="btnOutOfBrowser_Click" />

            
<!-- Popup 的 Demo -->
            
<Button Name="btnShowPopup" Margin="5" Content="弹出 Popup" Click="btnShowPopup_Click" />

            
<!-- NotificationWindow 的 Demo -->
            
<Button Name="btnShowNotificationWindow" Margin="5" Content="弹出 NotificationWindow" Click="btnShowNotificationWindow_Click" />

        
</StackPanel>
    
</Grid>
</navigation:Page>


NotificationWindowDemo.xaml.cs

代码
/*
 * NotificationWindow - 在 OOB 模式下显示通知窗口,也就是 toast
 
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

using System.Windows.Controls.Primitives;

namespace Silverlight40.OutOfBrowser
{
    
public partial class NotificationWindowDemo : Page
    {
        
public NotificationWindowDemo()
        {
            InitializeComponent();
        }

        
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            
if (App.Current.IsRunningOutOfBrowser)
                btnOutOfBrowser.Content 
= "卸载";
            
else
                btnOutOfBrowser.Content 
= "安装";
        }

        
private void btnOutOfBrowser_Click(object sender, RoutedEventArgs e)
        {
            
if (!App.Current.IsRunningOutOfBrowser && App.Current.InstallState == InstallState.NotInstalled)
                App.Current.Install();
            
else
                MessageBox.Show(
"已经安装,使用右键卸载");
        }

       
        
private void btnShowPopup_Click(object sender, RoutedEventArgs e)
        {
            
/*
             * Popup - 用于在 Silverlight 程序区域之内,Silverlight 内容之上显示内容,其通吃浏览器内外。来自 Silverlight 2.0
             *     Popup.Child - Popup 上显示的内容 
             *     Popup.IsOpen - 是否显示 Popup
             
*/

            Popup popup 
= new Popup();

            Border border 
= new Border();
            border.BorderBrush 
= new SolidColorBrush(Colors.Black);
            border.BorderThickness 
= new Thickness(5.0);

            StackPanel container 
= new StackPanel();
            container.Width 
= 320;
            container.Height 
= 240;
            container.Background 
= new SolidColorBrush(Colors.Yellow);

            TextBlock lblMsg 
= new TextBlock();
            lblMsg.Text 
= "Popup 信息";

            Button btnClose 
= new Button();
            btnClose.Content 
= "关闭";
            btnClose.Click 
+= (x, y) => { popup.IsOpen = false; };

            container.Children.Add(lblMsg);
            container.Children.Add(btnClose);
            border.Child 
= container;

            popup.Child 
= border;

            popup.VerticalOffset 
= 100;
            popup.HorizontalOffset 
= 100;

            popup.IsOpen 
= true;
        }
       
        
private void btnShowNotificationWindow_Click(object sender, RoutedEventArgs e)
        {
            
/*
             * NotificationWindow.Content - toast 所显示的内容
             * NotificationWindow.Show(int durationInMilliseconds) - 显示 toast,并在指定时间后隐藏 toast
             * 
             * 注:每个 Silverlight 应用程序在同一时间只能显示一个 toast 。如果在一个 toast 正在显示的同时调用 NotificationWindow.Show() 则会引发异常
             
*/

            
if (App.Current.IsRunningOutOfBrowser)
            {
                NotificationWindow notify 
= new NotificationWindow();
                notify.Width 
= 320;
                notify.Height 
= 80;

                TextBlock lblMsg 
= new TextBlock();
                lblMsg.Text 
= "NotificationWindow 信息";
                lblMsg.FontSize 
= 18;

                notify.Content 
= lblMsg;

                notify.Show(
3000);
            }
            
else
            {
                MessageBox.Show(
"请在浏览器外运行");
            }
        }
    }
}



4、演示如何实现自定义的 NotificationWindow
generic.xaml

代码
<ResourceDictionary
    
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys
="clr-namespace:System;assembly=mscorlib"
    xmlns:vsm
="clr-namespace:System.Windows;assembly=System.Windows"
    xmlns:local
="clr-namespace:Silverlight40.OutOfBrowser">

    
<ResourceDictionary.MergedDictionaries>
        
<!--
            自定义控件时,将 Style 放到 generic.xaml 之外的注意事项:generic.xaml 和 Style 的 xaml 文件均要设置为资源类型
        
-->
        
<ResourceDictionary Source="/Silverlight40;component/themes/CustomNotificationWindow.xaml"/>
    
</ResourceDictionary.MergedDictionaries>

</ResourceDictionary>


CustomNotificationWindow.xaml

代码
<ResourceDictionary
    
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys
="clr-namespace:System;assembly=mscorlib"
    xmlns:vsm
="clr-namespace:System.Windows;assembly=System.Windows"
    xmlns:local
="clr-namespace:Silverlight40.OutOfBrowser">

    
<Style TargetType="local:CustomNotificationWindow">
        
<Setter Property="IsTabStop" Value="False"/>
        
<Setter Property="Background" Value="Black"/>
        
<Setter Property="Template">
            
<Setter.Value>
                
<ControlTemplate TargetType="local:CustomNotificationWindow">
                    
<StackPanel>
                        
<!-- 关闭按钮 -->
                        
<Button Name="btnClose" Content="关闭" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="5" />
                        
<!-- toast 的标题 -->
                        
<TextBlock Text="{TemplateBinding Title}" Foreground="Red" FontWeight="Bold" FontSize="12" />
                        
<!-- toast 的正文 -->
                        
<TextBlock Text="{TemplateBinding Text}" FontSize="12" TextWrapping="Wrap" />
                    
</StackPanel>
                
</ControlTemplate>
            
</Setter.Value>
        
</Setter>
    
</Style>
    
</ResourceDictionary>


CustomNotificationWindow.cs

代码
/*
 * 本例演示如何实现自定的 NotificationWindow
 
*/

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Silverlight40.OutOfBrowser
{
    
public class CustomNotificationWindow : ContentControl
    {
        
public CustomNotificationWindow()
        {
            
// 设置控件的默认样式
            this.DefaultStyleKey = typeof(CustomNotificationWindow);
        }


        
// toast 的标题
        public string Title
        {
            
get { return (string)GetValue(CustomNotificationWindow.TitleProperty); }
            
set { SetValue(CustomNotificationWindow.TitleProperty, value); }
        }
        
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register
        (
            
"Title",
            
typeof(string),
            
typeof(CustomNotificationWindow),
            
new PropertyMetadata(OnTitlePropertyChanged)
        );
        
private static void OnTitlePropertyChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
        }


        
// toast 的正文
        public string Text
        {
            
get { return (string)GetValue(CustomNotificationWindow.TextProperty); }
            
set { SetValue(CustomNotificationWindow.TextProperty, value); }
        }
        
public static readonly DependencyProperty TextProperty = DependencyProperty.Register
        (
            
"Text",
            
typeof(string),
            
typeof(CustomNotificationWindow),
            
new PropertyMetadata(OnTextPropertyChanged)
        );
        
private static void OnTextPropertyChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
        }


        
//  UI 元素在应用程序中显示之前所调用的方法
        public override void OnApplyTemplate()
        {
            
base.OnApplyTemplate();

            
// Control.GetTemplateChild() - 在实例化的 ControlTemplate 可视化树中检索已命名的元素
            Button btnClose = GetTemplateChild("btnClose"as Button;
            
if (btnClose != null)
            {
                btnClose.Click 
+= (s, e) =>
                {
                    EventHandler
<EventArgs> handler = this.Closed;
                    
if (handler != null)
                        handler(
this, EventArgs.Empty);
                };
            }
        }

        
public event EventHandler<EventArgs> Closed;
    }
}


CustomNotificationWindowDemo.xaml

代码
<navigation:Page x:Class="Silverlight40.OutOfBrowser.CustomNotificationWindowDemo" 
           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"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title
="CustomNotificationWindowDemo Page">
    
<Grid x:Name="LayoutRoot">
        
<StackPanel HorizontalAlignment="Left">
            
<Button Name="btnOutOfBrowser" Margin="50" Click="btnOutOfBrowser_Click" />

            
<!-- 自定义 NotificationWindow 的 Demo -->
            
<Button Name="btnShowCustomNotificationWindow" Margin="5" Content="弹出 CustomNotificationWindow" Click="btnShowCustomNotificationWindow_Click" />

        
</StackPanel>
    
</Grid>
</navigation:Page>


CustomNotificationWindowDemo.xaml.cs

代码
/*
 * 本例演示如何使用自定的 NotificationWindow
 
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

namespace Silverlight40.OutOfBrowser
{
    
public partial class CustomNotificationWindowDemo : Page
    {
        
public CustomNotificationWindowDemo()
        {
            InitializeComponent();
        }

        
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            
if (App.Current.IsRunningOutOfBrowser)
                btnOutOfBrowser.Content 
= "卸载";
            
else
                btnOutOfBrowser.Content 
= "安装";
        }

        
private void btnOutOfBrowser_Click(object sender, RoutedEventArgs e)
        {
            
if (!App.Current.IsRunningOutOfBrowser && App.Current.InstallState == InstallState.NotInstalled)
                App.Current.Install();
            
else
                MessageBox.Show(
"已经安装,使用右键卸载");
        }


        
private void btnShowCustomNotificationWindow_Click(object sender, RoutedEventArgs e)
        {
            
// 实例化一个 NotificationWindow,并指定其宽和高
            NotificationWindow notify = new NotificationWindow();
            notify.Width 
= 320;
            notify.Height 
= 80;

            
// 将 NotificationWindow 的显示内容设置为自定义的内容
            CustomNotificationWindow custom = new CustomNotificationWindow();
            custom.Title 
= "我是标题";
            custom.Text 
= "我是内容";
            custom.Width 
= notify.Width;
            custom.Height 
= notify.Height;
            custom.Closed 
+= (x, y) => { notify.Close(); };

            notify.Content 
= custom;

            notify.Show(
3000);
        }
    }
}



OK
[源码下载]