WPF 給類庫設置設計時使用的資源字典


在開發 WPF 類庫時,由於類庫里面沒有存在 App.xaml.cs 文件,而在對單個 XAML 進行開發時,設計器將會因為找不到資源文件的存在,而拿不到資源。本文告訴大家簡單的方法,給設計器設置僅在設計時引用的資源

在 WPF 的 XAML 中,如果對每個 XAML 控件都引用相同的資源,此時設計時將可以愉快的跑起來,然而在運行時將會重復創建資源影響性能。在開發 WPF 應用時,在入口項目里面,因為入口處有 App.xaml 文件,在這個文件里面加上了各個項目的引用,此時設計器就能知道當前項目引用的 XAML 資源字典,因此設計器就能工作

但是在開發類庫的時候,類庫不知道最終的入口項目是哪個,因此也就不知道當前程序在運行的時候,將會找不到引用

最佳的方法是和 Blend 一樣,在設計時讓設計器引用上某些資源,這樣設計器就能工作

實現方法是在類庫里面添加特殊的文件,這個特殊的文件有文件夾和命名的要求,這是在 VisualStudio 的設計器里面寫常量固定的路徑

在項目里面新建 Properties 文件夾,在 Properties 文件夾里面新建 DesignTimeResources.xaml 資源字典文件,大概如下

這個文件的命名規則是有約定的,不推薦自己修改。在 csproj 上添加如下代碼

  <ItemGroup>
    <Page Update="Properties\DesignTimeResources.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
      <ContainsDesignTimeResources>true</ContainsDesignTimeResources>
    </Page>
  </ItemGroup>

上面代碼核心就是 ContainsDesignTimeResources 這個屬性。理論上可以給任意的 xaml 文件設置這個屬性,但是 XAML 設計器在很多 VS 版本上只讀取此路徑的文件

在 DesignTimeResources.xaml 資源字典添加對其他資源字典的引用,即可實現讓類庫的設計器找到資源,而在運行時是不會加載資源到內存

例如我新建了類庫項目 JeenalerenenearWerjilakaw 項目。我在 JeenalerenenearWerjilakaw 項目里面添加了資源字典 ColorBrushResourcesDictionary.xaml 資源字典,在里面存放顏色畫刷,代碼如下

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:JeenalerenenearWerjilakaw">
    <SolidColorBrush x:Key="Brush.ColorBrush.ThemeColorBrush">#FF565656</SolidColorBrush>
</ResourceDictionary>

而我期望在 JeenalerenenearWerjilakaw 項目的自定義控件 UserControl1.xaml 上使用這個 Brush.ColorBrush.ThemeColorBrush 資源,如下面代碼

  <Grid>
    <Border Background="{StaticResource Brush.ColorBrush.ThemeColorBrush}" Margin="10,10,10,10"></Border>
  </Grid>

此時的設計器和代碼都不能工作,將會在設計器提示找不到資源

接下來新建 Properties\DesignTimeResources.xaml 資源字典文件,在這個資源字典文件里面添加如下代碼

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="../ColorBrushResourcesDictionary.xaml"></ResourceDictionary>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

在 JeenalerenenearWerjilakaw 的 csproj 添加如下代碼

  <ItemGroup>
    <Page Update="Properties\DesignTimeResources.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
      <ContainsDesignTimeResources>true</ContainsDesignTimeResources>
    </Page>
  </ItemGroup>

當前的 csproj 的所有代碼看起來如下

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

  <ItemGroup>
    <Page Update="Properties\DesignTimeResources.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
      <ContainsDesignTimeResources>true</ContainsDesignTimeResources>
    </Page>
  </ItemGroup>
</Project>

以上代碼是用在 SDK 風格的 csproj 文件上,如果當前項目文件非 sdk 風格,請參閱 從以前的項目格式遷移到 VS2017 新項目格式

接下來保存代碼,然后關閉 VisualStudio 清理緩存文件,打開 VisualStudio 可以看到,當前設計器和代碼都能工作

本文代碼放在 githubgitee 歡迎下載執行

WPF Design Time Support (Part 2) · jbe2277/waf Wiki

然而在有 Resharper 的 VisualStudio 上,這個配置在 Resharper 2020 的一些版本是不認識的,此時將會讓 Resharper 找不到資源引用,而沒有自動跳轉和補全的功能。好在 Resharper 對於項目格式的支持不夠好,咱可以使用黑科技來解決此問題。在 Resharper 的 2021 版本也修了這個問題,因此在新版本的 Resharper 是不需要加以下代碼

在 Resharper 中,將會根據 ApplicationDefinition 定義去讀取應用資源文件,但是在讀取時將會忽略 Condition 內容。於是咱就可以嘗試創建一個叫 App_MakeReshaperHappy.xaml 的文件,用來讓 Resharper 開森。在 csproj 中添加如下代碼,用來引用應用資源,但實際上又不會用上此資源

    <ApplicationDefinition Include="App_MakeReshaperHappy.xaml" Condition="false">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </ApplicationDefinition>

上面代碼中,使用了 Condition 為 false 讓構建時實際忽略了此文件,否則將會在構建時報告不能在 WPF 類庫中定義 ApplicationDefinition 元素。為什么不能叫 App.xaml 文件?原因是在 SDK 風格的 csproj 中,默認將會加上 EnableDefaultApplicationDefinition 自動加上默認的 ApplicationDefinition 元素。只要有文件叫 App.xaml 的,那么將會自動識別為 ApplicationDefinition 元素,此元素將會讓 WPF 構建時報告不能在類庫中定義。而如果設置 EnableDefaultApplicationDefinition 為 false 那 Resharper 又會不認此文件,經過了 lsj 工具人的摸索,發現使用上文方法是最穩的

App_MakeReshaperHappy.xaml 文件里面存放以下代碼,用來讓 Resharper 智能感知能在設計時找到資源

<Application x:Class="App_MakeReshaperHappy" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!--這個文件只是為了讓Reshaper的智能感知開心-->
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!--以下替換為你自己的路徑,我推薦引用的是設計時資源文件-->
                <ResourceDictionary Source="Properties/DesignTimeResources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

以上代碼必須要自己定義類型,然后繼承 Application 同時有 x:Class 內容才可以。這個文件的文件名和類名要求一定包含 App 這三個字符,同時文件名和類名需要相同

以上代碼放在 githubgitee 歡迎下載執行


免責聲明!

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



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