WPF之神奇的資源


WPF中的資源有兩種,一種稱為"程序集資源"(assembly resource),另一種稱為"對象資源"(object resource)也稱為"邏輯資源",WPF中統稱后者為"邏輯資源"。

一、程序集資源
應用程序中的XAML、圖片、音頻、視頻等文件,都可以將其作為程序集資源組織起來。
程序集資源可以以以下3種方式打包:
1.資源文件(Resource File):直接嵌入到程序集中。
2.內容文件(Content File):該文件的相關信息會編譯到程序集中,如文件的相對位置。
3.Site of Origin文件:不參加編譯,應用程序不知道該文件是否存在。

資源文件
向項目中添加一個jpg的圖片,默認的Build Action就為Resource,在Xaml中的2種使用方式如下:

        <Image Source="1.jpg" />
        <Image  Source="pack://application:,,,/1.jpg"/>

 答疑:
屬性中的Build Action中有一個Embedded Resource和Resource,區別呢?
兩者都可以將文件編譯到程序集資源中去,前者用於Winform項目中嵌入程序集資源,在WPF中則選擇后者。

 

內容文件
右鍵文件設置Build Action屬性為Content,同時設置屬性Copy to Output Directory 設置為Copy always或者Copy if newer,則可以復制到bin\debug下。

     <Image Source="Images/1.jpg"></Image>
     <Image Source="/Images/2.jpg" Grid.Row="1"></Image>

以上兩個方式均可以顯示輸出為Content的圖片。

 

Site of Origin文件
Site of Orign文件根本不參加編譯,應用程序編譯時候不知道該文件是否存在,只有運行時候才知道。
配置此類文件,右鍵屬性設置Build Actoin為None,Copy to Output Directory設置為Copy always或者Copy if newer。通過代碼訪問需要使用GetRemoteStream方法。

        Uri uri = new Uri("/siteoforiginfile.xaml", UriKind.Relative);
            StreamResourceInfo info = Application.GetRemoteStream(uri);
            System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
            Page page = (Page)reader.LoadAsync(info.Stream);
            this.siteoforiginfileframe.Content = page;

 

Uri語法
Uri可以通過當前程序集、被引用的程序集、相對程序集的一個位置和任意位置標識訪問資源。
WPF中的Uri由3部分組成,第一個部分的協議是pack;第2個部分成為"authority",有兩種值:一是application://,表示編譯時知道的文件,主要指資源和內容文件;二是siteoforign://,表示Site of Origin文件;第3部分是路徑,如果是引用程序集中資源,情況會稍微復雜一點。路徑必須包含引用的程序集名稱和一個Component標識,表示引用的不是本地程序集的資源,有時還需要加上版本信息。
WPF中的路徑分為相對和絕對路徑。WPF中的默認Uri設置是pack://application:,,,,因此引用site of orign文件必須要使用絕對路徑。

pack://application:,,,/ResourceFile.xaml
/ResouceFile.xaml

第一種為絕對路徑,第二種為相對路徑。

 <DockPanel>
    <StackPanel DockPanel.Dock="Top">

      <GroupBox Header="Absolute Pack URIs">
        <StackPanel>
          <Frame Source="pack://application:,,,/ResourceFile.xaml" />
          <Frame Source="pack://application:,,,/Subfolder/ResourceFile.xaml" />
          <Frame Source="pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml" />
          <Frame Source="pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml" />
          <Frame Source="pack://application:,,,/ReferencedAssembly;v1.0.0.1;component/ResourceFile.xaml" />
          <Frame Source="pack://application:,,,/ContentFile.xaml" />
          <Frame Source="pack://application:,,,/Subfolder/ContentFile.xaml" />
          <Frame Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
          <Frame Source="pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml" />
        </StackPanel>
      </GroupBox>

      <GroupBox Header="Relative Pack URIs">
        <StackPanel>
          <Frame Source="/ResourceFile.xaml" />
          <Frame Source="/Subfolder/ResourceFile.xaml" />
          <Frame Source="/ReferencedAssembly;component/ResourceFile.xaml" />
          <Frame Source="/ReferencedAssembly;component/Subfolder/ResourceFile.xaml" />
          <Frame Source="/ReferencedAssembly;v1.0.0.1;component/ResourceFile.xaml" />
          <Frame Source="/ContentFile.xaml" />
          <Frame Source="/Subfolder/ContentFile.xaml" />
          <Frame Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
          <Frame Source="pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml" />
        </StackPanel>
      </GroupBox>

    </StackPanel>

    <GroupBox Header="Version-Specified Pack URIs">
      <DockPanel>
        <Button DockPanel.Dock="Top" Click="click0">Get Resource File in Reference Assembly v1.0.0.0</Button>
        <Button DockPanel.Dock="Top" Click="click1">Get Resource File in Reference Assembly v1.0.0.1</Button>
        <Frame Name="frame" NavigationUIVisibility="Hidden" />
      </DockPanel>
    </GroupBox>

  </DockPanel>
   void click0(object sender, RoutedEventArgs e) {
            Uri uri = new Uri("/VersionedReferencedAssembly;v1.0.0.0;component/ResourceFile.xaml", UriKind.RelativeOrAbsolute);
            this.frame.Source = uri;
        }

        void click1(object sender, RoutedEventArgs e)
        {
            Uri uri = new Uri("/VersionedReferencedAssembly;v1.0.0.1;component/ResourceFile.xaml", UriKind.RelativeOrAbsolute);
            this.frame.Source = uri;
        }

此示例為微軟提供的Uri的用法,幾乎涵蓋了所有的使用方法,源碼下載如下:
WPFUriSample


WPF中的URI處理順序
WPF中有兩個處理系統,即siteoforigin:///和applicatoin:///,前者按照提供的路徑查找SiteofOrigin文件,后者的比較復雜:
1。先查找路徑是否為內容文件
2.如果未找到,則繼續在程序集的資源中查找;如果找到則為資源問及那;
3.如果未找到,則為無效。

邏輯資源(對象資源)
看如下例子:

    <Window.Resources>
        <ImageBrush x:Key="TileBrush" x:Shared ="True"  TileMode="Tile"
                ViewportUnits="Absolute" Viewport="0 0 32 32"
                ImageSource="happyface.jpg" Opacity="0.3" ></ImageBrush>
    </Window.Resources>
  <Button Background="{StaticResource TileBrush}" Padding="5"
              FontWeight="Bold" FontSize="14" Margin="5" Click="Button_Click">A Tiled Button 靜態資源引用</Button>

以上例子在Resource中定義了一個畫刷資源,在Button中使用其設置背景顏色,通過"{StaticResouce ReourceKey}"語法進行資源的引用。

不僅僅畫刷(或者是應用於樣式)可以作為資源,普通的.Net對象也可用於資源,如下:

xmlns:s ="clr-namespace:System;assembly=mscorlib"

在Windows標簽中引用System命名空間,使用如下:

    <Window.Resources>
        <s:String x:Key="ButtonContent">
            邏輯資源Demo
        </s:String>
    </Window.Resources>

調用資源,作為文本顯示

<Button Grid.Row="2" Margin="5" Content="{StaticResource ButtonContent}" Click="Button_Click_1" />


靜態資源和動態資源

 WPF提供了兩種訪問邏輯資源的方式,一是靜態資源,通過StaticResource標記擴展來實現,前面引用資源的方式均為此方式;二是動態資源,通過DynamicResource標記擴展
來實現。
靜態資源和動態的資源主要區別在於,靜態資源只從資源字典中查找一次資源,后者在應用程序需要時查找資源.

<Button Background="{StaticResource TileBrush}" Padding="5"
FontWeight="Bold" FontSize="14" Margin="5" Click="Button_Click">A Tiled Button 靜態資源引用</Button>
<Button Grid.Row="1" Background="{DynamicResource TileBrush}" Padding="5"
FontWeight="Bold" FontSize="14" Margin="5" Click="Button_Click">A Tiled Button 動態資源引用</Button>

        <Button Grid.Row="3"  Margin="5"Click="Button_Click" />

 

例子中的兩個按鈕一個是靜態資源方式引用,一種是動態資源方式引用,在Click中修改資源如下:

            ImageBrush brush = (ImageBrush)this.Resources["TileBrush"];
            ImageBrush newbrush = brush.Clone();
            newbrush.Viewport = new Rect(0, 0, 5, 5);
            this.Resources["TileBrush"] = newbrush;

點擊按鈕會神奇的發現,動態資源方式的按鈕的背景會變化哦.
注意:切忌,最后一句代碼,必須要重新給舊的資源對象賦值.

共享資源
默認情況下,當有一個資源被應用到多處時使用的都是一個對象實例,這是極好的了.如果希望應用程序在使用資源的每處都有一個不同的對象實例,可以在資源中標記
x:Shared="False".
例如將Image作為資源,由於其派生自Visual類,會被添加到邏輯樹和可視化樹中,因此不能將Image的對象作為資源多次使用,否則會拋出異常哦.但是可以將Image資源
標記成x:Shared="False",這樣在應用這個資源時實際創建了不同的對象實例。

使用ResourceDictionary組織管理資源
WPF中提供了ResourceDictionary(資源字典)類型的XAML文件組織資源,右鍵項目ADD菜單-->Resource Dictionary即可創建一個資源字典,資源可以分類別
放在同一個資源文件。如下降畫刷資源放在Brushes.xaml文件中:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local ="clr-namespace:mumu_resourcesLib">
    <ImageBrush
      x:Key="SadFaceBrush"
      TileMode="Tile"
      ViewportUnits="Absolute" Viewport="0 0 32 32"
      ImageSource="sadface.jpg" Opacity="0.3">
    </ImageBrush>
</ResourceDictionary>

在App.xaml文件中通過MergedDictionaries包含資源字典文件,這樣應用程序就可以訪問Brushes.xaml文件中的資源了:

<Application x:Class="mumu_shareresources.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Brushes.xaml"/>
            </ResourceDictionary.MergedDictionaries>    
        </ResourceDictionary>
    </Application.Resources>
</Application>

使用如下:

 <Button Background="{StaticResource SadFaceBrush}" />



程序集之間共享資源:
有如下目錄結構的程序

 ResourceDemo項目為WPF Application,ResourceLibrary為WPF Libiary。在ResourceLibrary中有Brushes.xaml資源文件,代碼如下:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ImageBrush
      x:Key="SadFaceBrush"
      TileMode="Tile"
      ViewportUnits="Absolute" Viewport="200 200 200 200"
      ImageSource="1.jpg">
    </ImageBrush>
</ResourceDictionary>

在APP.xaml中引用資源文件:

<Application x:Class="WpfApplication9.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary  Source="/ResourceLibrary;component/Brushes.xaml"></ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

程序集之間引用使用"/程序集;component/資源文件"這樣的語法來進行調用。
使用方法還是這樣:

 <Button Background="{StaticResource SadFaceBrush}"></Button>


好了,WPF的資源介紹暫且到這里,歡迎大家討論分享.




免責聲明!

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



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