资源引用

WPF中的资源包含很多,如图片、字体、声音,以及样式、模板等很多,在使用的时候常常出现很多问题。

绑定图片路径

需求:程序发布后,可以更换图片

一定要使用绝对路径,相对路径不行

前端

<UserControl xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"  xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"  x:Class="OESTS.Modules.Login.Views.LoginView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"   
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:Control="clr-namespace:OESTS.Control;assembly=OESTS.Control"
             xmlns:core="clr-namespace:OESTS.Core.Events;assembly=OESTS.Core"
             prism:ViewModelLocator.AutoWireViewModel="True" Margin="0"
             Width="1280" Height="720">
    <UserControl.Background>
        <ImageBrush ImageSource="{Binding BackgroundImagesource}" />
    </UserControl.Background>

后端

   public class LoginViewModel : RegionViewModelBase
   {


       private string _backgroundImagesource;
       public string BackgroundImagesource
       {
           get { return _backgroundImagesource; }
           set { SetProperty(ref _backgroundImagesource, value); }
       }

       public LoginViewModel() 
       {
            //注意,一定要使用绝对路径,相对路径不行
           //加载背景图,在exe文件的 Assets/bg.png
           BackgroundImagesource = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Assets/bg.png");
       }

   }

资源路径

在WPF开发中,对资源的管理非常重要,当我们存在多个项目时,最好是把所有的资源都放在一个基础项目中进行管理,方便维护。

正确的做法使用

pack://application:,,,/程序集名称;component/资源路径名

图片资源路径

存在两个项目

  • 基础项目名称:Demo.Infrastructure
  • 主项目 Demo

所有的资源在 Demo.Infrastructure 中定义

  • 正确的使用
    <UserControl.Background>
        <!---->
        <ImageBrush ImageSource="pack://application:,,,/
        Demo.Infrastructure;component/images/login_bg.png"/>
    </UserControl.Background>
  • 错误的使用(不加 pack://application:,,,)此时为相对路径,在编辑模式下可以看到图片,但是运行后不显示
 <UserControl.Background>
        <!---->
        <ImageBrush ImageSource="/
        Demo.Infrastructure;component/images/login_bg.png"/>
    </UserControl.Background>
  • 错误的使用(不加 pack://application:,,, 和命名空间)
 <UserControl.Background>
        <!---->
        <ImageBrush ImageSource="images/login_bg.png"/>
    </UserControl.Background>

字体资源路径

可以下载阿里巴巴的字体文件,下载后将ttf文件拷贝到项目中


<TextBlock Text="&#xe657;" FontFamily="{StaticResource iconfont}" FontSize="14" Foreground="Red" VerticalAlignment="Center" />
<TextBlock Text="&#xe657;" FontFamily="/OESTS.Modules.Login;component/fonts/#iconfont" FontSize="14" Foreground="Red" VerticalAlignment="Center" />
<TextBlock Text="&#xe657;" FontFamily="/fonts/#iconfont" FontSize="14" Foreground="Red" VerticalAlignment="Center"/>

LoadComponent使用的路径

加载组件函数,可以加载一个xaml文件,这里页存在一个资源路径的问题,此方法仅能使用相对路径,不能使用绝对路径

案例:需求加载一个流文档控件的文件资源,

文件名为flowdoc.xaml,如下

<FlowDocument 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"
                TextOptions.TextFormattingMode="Display" >
    <Paragraph>
        <Run Text="加载测试" ></Run>
    </Paragraph>
</FlowDocument>
  • 当只有一个项目时,若文件存在项目的resources文件中,加载方式如下
  FlowDocument doc = (FlowDocument)Application.LoadComponent(new Uri("/resources/flowdoc.xaml", UriKind.Relative));
  • 当存在多个项目,如使用了Prism框架,在一个模块项目中加载时(模块项目的程序集为:DemoModule)
//正确的做法
FlowDocument doc = (FlowDocument)Application.LoadComponent(
new Uri("/DemoModule;component/resources/flowdoc.xaml",
UriKind.Relative));

//错误的做法,不能加pack://application:,,,,加了后为绝对路径
FlowDocument doc = (FlowDocument)Application.LoadComponent(
new Uri("pack://application:,,,DemoModule;component/resources/flowdoc.xaml", 
UriKind.Relative));

资源的引用方式

  • 本地添加模板目录:分别创建模板对象。
  • App.xaml中添加模板目录,创建全局模板对象,导致大家的数据相同。
  • 对于样式、转换器、模板选择器等,在App.xaml添加目录比较合适。
  • 对于模板的使用,在本地添加模板目录不会出现问题。
  • 如果两者都添加,本地添加的起作用。

场景描述: 当前有两个页面(AView,BView)的布局相同,数据不同,定义了一个通用模板为 ContentTemplate, 定义了通用模板,key 为 contentView

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ScreenControlE" >
    <Grid x:Key="contentView">

       <TextBlock Text="{Binding Path=Content}" FontSize="14" Foreground="Red" VerticalAlignment="Center" />

    </Grid>
</ResourceDictionary>

A、B页面在本地添加模板目录

  • A、B页面的前端(这里使用了Prsim框架),在本地添加了资源目录,并引用 contentView,此时两个页面显示正常,分别显示自己的内容

<UserControl x:Class=" ScreenControlE.Views.NCCView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"       
             prism:ViewModelLocator.AutoWireViewModel="True">
    <UserControl.Resources>
        <ResourceDictionary Source="/Themes/ContentTemplate.xaml"/>
    </UserControl.Resources>
    <Grid>
        <ContentControl x:Name="ncc_contentCrl" Content="{StaticResource contentView }"/>
    </Grid>
</UserControl>

在App.xaml中添加模板的目录

  • App.xaml
<prism:PrismApplication x:Class="ScreenControlE.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:ScreenControlE"
             xmlns:prism="http://prismlibrary.com/" >
    <Application.Resources>
		<ResourceDictionary Source="/Themes/ContentTemplate.xaml"/>

    </Application.Resources>
</prism:PrismApplication>

  • A、B页面的前端(这里使用了Prsim框架),直接引用 contentView

<UserControl x:Class=" ScreenControlE.Views.NCCView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"       
             prism:ViewModelLocator.AutoWireViewModel="True">
 
    <Grid>
        <ContentControl x:Name="ncc_contentCrl" Content="{StaticResource contentView }"/>
    </Grid>
</UserControl>

  • 两个页面显示了相同的内容,在App.xaml中添加的相当于创建了一个全局变量的对象

  • ViewModel(A为例)

public class AViewModel : ViewModelBase
{
    public string Content { get; set; } = "A模板"
}