與眾不同 windows phone (38) - 8.0 關聯啟動: 使用外部程序打開一個文件或URI, 關聯指定的文件類型或協議


[源碼下載]


與眾不同 windows phone (38) - 8.0 關聯啟動: 使用外部程序打開一個文件或URI, 關聯指定的文件類型或協議



作者:webabcd


介紹
與眾不同 windows phone 8.0 之 關聯啟動

  • 使用外部程序打開一個文件
  • 使用外部程序打開一個 Uri
  • 關聯指定的文件類型
  • 關聯指定的協議



示例
1、演示如何使用外部程序打開一個文件
AssociationLaunching/LaunchFile.xaml

<phone:PhoneApplicationPage
    x:Class="Demo.AssociationLaunching.LaunchFile"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <Grid Background="Transparent">
        <StackPanel>
            
            <TextBlock Name="lblMsg" Margin="0 0 0 10" />

            <Button Content="打開一個 .log 文件" Name="btnLaunchFile" Click="btnLaunchFile_Click" />
            
        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

AssociationLaunching/LaunchFile.xaml.cs

/*
 * 演示如何使用外部程序打開一個文件
 */

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Windows.Storage;
using System.IO;
using System.Text;

namespace Demo.AssociationLaunching
{
    public partial class LaunchFile : PhoneApplicationPage
    {
        public LaunchFile()
        {
            InitializeComponent();
        }

        private async void btnLaunchFile_Click(object sender, RoutedEventArgs e)
        {
            // 在 ApplicationData 的根目錄下寫一個 myLog.log 文件
            StorageFolder applicationFolder = ApplicationData.Current.LocalFolder;
            StorageFile storageFile = await applicationFolder.CreateFileAsync("myLog.log", CreationCollisionOption.ReplaceExisting);
            using (Stream stream = await storageFile.OpenStreamForWriteAsync())
            {
                byte[] content = Encoding.UTF8.GetBytes("hello webabcd");
                await stream.WriteAsync(content, 0, content.Length);
            }

            // 啟動與 .log 類型文件關聯的默認應用程序,來打開指定的文件
            Windows.System.Launcher.LaunchFileAsync(storageFile);
        }
    }
}


2、演示如何使用外部程序打開一個 Uri(自定義協議)
AssociationLaunching/LaunchUri.xaml

<phone:PhoneApplicationPage
    x:Class="Demo.AssociationLaunching.LaunchUri"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <Grid Background="Transparent">
        <StackPanel>

            <TextBlock Name="lblMsg" Margin="0 0 0 10" />

            <Button Content="啟動一個協議名為 webabcd 的 uri" Name="btnLaunchUri" Click="btnLaunchUri_Click" />

        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

AssociationLaunching/LaunchUri.xaml.cs

/*
 * 演示如何使用外部程序打開一個 Uri(自定義協議)
 */

using System.Windows;
using Microsoft.Phone.Controls;
using Windows.Networking.Proximity;

namespace Demo.AssociationLaunching
{
    public partial class LaunchUri : PhoneApplicationPage
    {
        public LaunchUri()
        {
            InitializeComponent();
        }

        private void btnLaunchUri_Click(object sender, RoutedEventArgs e)
        {
            // 使用外部程序打開指定的 Uri(自定義協議,注意這里沒有“//”)
            Windows.System.Launcher.LaunchUriAsync(new System.Uri("webabcd:hello webabcd"));



            // nfc 方式啟用另一台 wp nfc 設備打開指定的 Uri(需要在 manifest 中聲明 ID_CAP_NETWORKING 和 ID_CAP_PROXIMITY)
            ProximityDevice nfcDevice = ProximityDevice.GetDefault();
            if (nfcDevice != null)
            {
                long Id = nfcDevice.PublishUriMessage(new System.Uri("webabcd:hello webabcd"));
            }
        }
    }
}


3、演示如何關聯指定的文件類型(即用本程序打開指定類型的文件)
AssociationLaunching/FileTypeAssociation.xaml

<phone:PhoneApplicationPage
    x:Class="Demo.AssociationLaunching.FileTypeAssociation"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <Grid Background="Transparent">
        <StackPanel>
            
            <TextBlock Name="lblMsg" TextWrapping="Wrap" />
            
            <TextBlock TextWrapping="Wrap" Margin="0 10 0 0">
                <Run>本程序可以打開 .log 類型的文件</Run>
                <LineBreak />
                <Run>測試方法:通過 LaunchFile.xaml 打開一個 .log 類型的文件</Run>
            </TextBlock>
            
        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

AssociationLaunching/FileTypeAssociation.xaml.cs

/*
 * 演示如何關聯指定的文件類型(即用本程序打開指定類型的文件)
 * 
 * 
 * 由於配置為 NavUriFragment="fileToken=%s",所以本 app 打開某類型的文件會通過 /FileTypeAssociation?fileToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 啟動
 * 相關的 UriMapper 參見 MyUriMapper.cs
 * 
 * 
 * 注:
 * 需要在 manifest 中增加類似如下的配置
 *  <Extensions>
      <!--
          NavUriFragment="fileToken=%s" 的意思是:
          1、某 app 啟動外部程序打開 .xxx 文件時會傳遞文件的 token
          2、如果最終是由本 app 打開 .xxx 文件,則本 app 會通過 /FileTypeAssociation?fileToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 啟動
      -->
      <FileTypeAssociation TaskID="_default" Name="myFileTypeAssociation" NavUriFragment="fileToken=%s">
        <Logos>
          <!--相關類型的文件顯示在電子郵件附件中的圖標,33x33 像素,其會顯示在白色的背景前-->
          <Logo Size="small" IsRelative="true">Assets/AppIcon_33x33.png</Logo>
          <!--相關類型的文件顯示在 Office 中心列表視圖中的圖標,69x69 像素,其會顯示在白色的背景前-->
          <Logo Size="medium" IsRelative="true">Assets/AppIcon_69x69.png</Logo>
          <!--相關類型的文件顯示在瀏覽器下載中的圖標,176x176 像素,其會顯示在白色的背景前-->
          <Logo Size="large" IsRelative="true">Assets/AppIcon_176x176.png</Logo>
        </Logos>
        <SupportedFileTypes>
          <!--關聯的文件類型列表-->
          <FileType ContentType="text/plain">.log</FileType>
          <FileType ContentType="application/rar">.rar</FileType>
        </SupportedFileTypes>
      </FileTypeAssociation>
    </Extensions>
 */

using System;
using System.Collections.Generic;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Windows.Phone.Storage.SharedAccess;
using Windows.Storage;
using Windows.Storage.Streams;
using System.IO;
using System.Text;

namespace Demo.AssociationLaunching
{
    public partial class FileTypeAssociation : PhoneApplicationPage
    {
        public FileTypeAssociation()
        {
            InitializeComponent();
        }

        protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            IDictionary<string, string> queryStrings = this.NavigationContext.QueryString;

            if (queryStrings.ContainsKey("fileToken"))
            {
                // 獲取需要打開的文件的 token
                string fileToken = queryStrings["fileToken"];
                // 保存需要打開的文件到本 app 的 ApplicationData
                await SharedStorageAccessManager.CopySharedFileAsync(ApplicationData.Current.LocalFolder, "myLog2.log", NameCollisionOption.ReplaceExisting, fileToken);
                // 獲取文件的文件名稱
                string fileName = SharedStorageAccessManager.GetSharedFileName(fileToken);

                lblMsg.Text = "fileName: " + fileName;
                lblMsg.Text += Environment.NewLine;

                // 獲取 ApplicationData 中指定的文件
                StorageFolder applicationFolder = ApplicationData.Current.LocalFolder;
                StorageFile storageFile = await applicationFolder.GetFileAsync("myLog2.log");

                // 顯示文件內容
                IRandomAccessStreamWithContentType accessStream = await storageFile.OpenReadAsync();
                using (Stream stream = accessStream.AsStreamForRead((int)accessStream.Size))
                {
                    byte[] content = new byte[stream.Length];
                    await stream.ReadAsync(content, 0, (int)stream.Length);

                    lblMsg.Text += Encoding.UTF8.GetString(content, 0, content.Length);
                }
            }

            base.OnNavigatedTo(e);
        }
    }
}


4、演示如何關聯指定的協議(即用本程序處理指定的協議)
AssociationLaunching/ProtocolAssociation.xaml

<phone:PhoneApplicationPage
    x:Class="Demo.AssociationLaunching.ProtocolAssociation"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <Grid Background="Transparent">
        <StackPanel>

            <TextBlock Name="lblMsg" TextWrapping="Wrap" />

            <TextBlock TextWrapping="Wrap" Margin="0 10 0 0">
                <Run>本程序可以處理 webabcd 協議</Run>
                <LineBreak />
                <Run>測試方法:通過 LaunchUri 打開一個名為 webabcd 的協議</Run>
            </TextBlock>
            
        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

AssociationLaunching/ProtocolAssociation.xaml.cs

/*
 * 演示如何關聯指定的協議(即用本程序處理指定的協議)
 * 
 * 
 * 由於配置為 NavUriFragment="encodedLaunchUri=%s",所以本 app 打開某協議會通過 /Protocol?encodedLaunchUri=webabcd:xxxxxxxxxx 啟動
 * 相關的 UriMapper 參見 MyUriMapper.cs
 * 
 * 
 * 注:
 * 需要在 manifest 中增加類似如下的配置
 *  <Extensions>
      <!--
          Name 是協議名稱,對於本例來說協議的示例為“webabcd:hello webabcd”,注意其沒有“//”
      -->
      <Protocol TaskID="_default" Name="webabcd" NavUriFragment="encodedLaunchUri=%s" />
    </Extensions>
 */

using System.Collections.Generic;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;

namespace Demo.AssociationLaunching
{
    public partial class ProtocolAssociation : PhoneApplicationPage
    {
        public ProtocolAssociation()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // 顯示協議的詳細信息
            IDictionary<string, string> queryStrings = this.NavigationContext.QueryString;
            if (queryStrings.ContainsKey("protocol"))
            {
                lblMsg.Text = queryStrings["protocol"];
            }

            base.OnNavigatedTo(e);
        }
    }
}


自定義 UriMapper,用於處理當本 app 由文件打開或協議打開或鏡頭擴展打開或圖片擴展打開時,導航到相關的處理頁面
MyUriMapper.cs

/*
 * 自定義 UriMapper,用於處理當本 app 由文件打開或協議打開或鏡頭擴展打開或圖片擴展打開時,導航到相關的處理頁面
 * 
 * 注:
 * 要使此 UriMapper 有效,需要在 App.xaml.cs 中增加 RootFrame.UriMapper = new Demo.MyUriMapper();
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Windows.Navigation;
using Windows.Phone.Storage.SharedAccess;

namespace Demo
{
    public class MyUriMapper : UriMapperBase
    {
        public override Uri MapUri(Uri uri)
        {
            string tempUrl = HttpUtility.UrlDecode(uri.ToString());

            // 由文件啟動本 app 時會通過 /FileTypeAssociation?fileToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 啟動
            if (tempUrl.StartsWith("/FileTypeAssociation"))
            {
                // 獲取 fileToken
                int fileTokenIndex = tempUrl.IndexOf("fileToken=") + 10;
                string fileToken = tempUrl.Substring(fileTokenIndex);

                // 獲取相關的文件名
                string fileName = SharedStorageAccessManager.GetSharedFileName(fileToken); // myLog.log

                // 獲取相關的文件名的擴展名
                string fileType = Path.GetExtension(fileName);

                // 根據文件類型的不同導航到不同的處理頁面
                switch (fileType)
                {
                    case ".log":
                        return new Uri("/AssociationLaunching/FileTypeAssociation.xaml?fileToken=" + fileToken, UriKind.Relative);
                    default:
                        return new Uri("/MainPage.xaml", UriKind.Relative);
                }
            }
            // 由協議啟動本 app 時會通過 /Protocol?encodedLaunchUri=webabcd:xxxxxxxxxx 啟動
            else if (tempUrl.StartsWith("/Protocol"))
            {
                // 獲取協議的詳細信息
                int protocolIndex = tempUrl.IndexOf("encodedLaunchUri=") + 17;
                string protocol = tempUrl.Substring(protocolIndex);

                // 導航到處理 webabcd 協議的處理頁面
                return new Uri("/AssociationLaunching/ProtocolAssociation.xaml?protocol=" + protocol, UriKind.Relative);
            }
            // 由鏡頭擴展啟動本 app 時會通過 /MainPage.xaml?Action=ViewfinderLaunch 啟動
            else if (tempUrl.Contains("Action=ViewfinderLaunch"))
            {
                return new Uri("/CameraAndPhoto/LensExtensibility.xaml?fromLens=true", UriKind.Relative);
            }
            // 由圖片擴展之“共享...”啟動本 app 時會通過 /MainPage.xaml?Action=ShareContent&FileId={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 啟動
            else if (tempUrl.Contains("Action=ShareContent"))
            {
                string fileId = tempUrl.Substring(tempUrl.IndexOf("FileId=") + 7).Replace("{", "").Replace("}", "");
                return new Uri("/CameraAndPhoto/PhotoExtensibility.xaml?type=share&token=" + fileId, UriKind.Relative);
            }
            // 由圖片擴展之“編輯...”啟動本 app 時會通過 /MainPage.xaml?Action=EditPhotoContent&FileId={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 啟動
            else if (tempUrl.Contains("Action=EditPhotoContent"))
            {
                string fileId = tempUrl.Substring(tempUrl.IndexOf("FileId=") + 7).Replace("{", "").Replace("}", "");
                return new Uri("/CameraAndPhoto/PhotoExtensibility.xaml?type=edit&token=" + fileId, UriKind.Relative);
            }
            // 由圖片擴展之“自動上傳”啟動本 app 時會通過 /MainPage.xaml?Action=ConfigurePhotosUploadSettings 啟動
            else if (tempUrl.Contains("Action=ConfigurePhotosUploadSettings"))
            {
                return new Uri("/CameraAndPhoto/PhotoAutoUpload.xaml?fromConfig=true", UriKind.Relative);
            }
            // 在鎖屏設置界面,如果將本 app 設置為背景提供程序,則鎖屏界面上會有一個名為“打開應用”的按鈕,點擊后會通過 /MainPage.xaml?WallpaperSettings=1 啟動本 app
            else if (tempUrl.Contains("WallpaperSettings=1"))
            {
                return new Uri("/Others/LockScreen.xaml?WallpaperSettings=1", UriKind.Relative);
            }

            return uri;
        }
    }
}

將此 app 的 UriMapper 設置為我們自定義的 UriMapper
App.xaml.cs

private void InitializePhoneApplication()
{
    // 設置本 app 的 UriMapper
    RootFrame.UriMapper = new Demo.MyUriMapper();
}



OK
[源碼下載]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM