28

I created a class library which is contained of WPF Windows and some user controls inherited from my c# classes that helps me to customize certain wpf controls.

Now I want to add ResourceDictionary, to help me share styles between my wpf classes. Is it possible?

Thx.


EDIT: resource dictionary file located in MY.WpfPresentation.Main project (named Styles.xaml):

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
                xmlns:dxgt="http://schemas.devexpress.com/winfx/2008/xaml/grid/themekeys"
                xmlns:MYNetMisc="clr-namespace:MY.Net.Misc;assembly=MY.Net"
                >
    <Style x:Key="customRowStyle" BasedOn="{StaticResource {dxgt:GridRowThemeKey ResourceKey=RowStyle}}" TargetType="{x:Type dxg:GridRowContent}">
        <Setter Property="Foreground" Value="{Binding Path=DataContext.balance, Converter={MYNetMisc:BalanceToColor OnlyNegative=false}}" />
    </Style>
</ResourceDictionary>

using it:

<MYNetPresentation:frmDockBase.Resources>       
    <ResourceDictionary x:Key="style">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/MY.WpfPresentation.Main;component/Styles.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
    <DataTemplate x:Key="TabTemplate">
        <dxlc:LayoutControl Padding="0" ScrollBars="None" Background="Transparent">
            <Image Source="/Images/Icons/table-32x32.png" Width="12" Height="12" />
            <TextBlock Text="{Binding}" HorizontalAlignment="Left" VerticalAlignment="Center" />
        </dxlc:LayoutControl>
    </DataTemplate>

</MYNetPresentation:frmDockBase.Resources>
davor
  • 939
  • 2
  • 14
  • 31

8 Answers8

34

create a resource dictionary like this one

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

  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <!-- Common base theme -->
      <ResourceDictionary Source="pack://application:,,,/Another.AssemblyName;component/YourResDictionaryFolder/OtherStyles.xaml" />
      <ResourceDictionary Source="pack://application:,,,/Another.AssemblyName;component/YourResDictionaryFolder/AnotherStyles.xaml" />
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>

  <!-- store here your styles -->

</ResourceDictionary>

and you can put it where you want

<Window x:Class="DragMoveForms.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window2"
        Height="300"
        Width="300">

  <Window.Resources>
    <ResourceDictionary Source="pack://application:,,,/Your.Base.AssemblyName;component/YourResDictionaryFolder/Dictionary1.xaml" />
  </Window.Resources>

  <Grid>

  </Grid>
</Window>
punker76
  • 14,326
  • 5
  • 58
  • 96
  • 2
    well, the problem is that I don't see ResourceDictionary when I try to add a new item to project. – davor Nov 17 '11 at 20:34
  • 1
    if your solution is a wpf solution -> right mouse at projectname in solution explorer -> Add -> Resourve Dictionary, or you can add a empty file named to YourName.xaml and put the ResourceDictionary tag in it – punker76 Nov 17 '11 at 20:45
  • I can see ResourceDictionary on Add->... only if my project is WPF application. So, I created new file and named it Styles.xaml but now I'm receiving exception: 'Resources' property has already been set on – davor Nov 17 '11 at 21:45
  • ah, you must move your datatemplate in the resourcedictionary tag, look at your first post – punker76 Nov 17 '11 at 22:18
  • 1
    great answer, but important to note: do not include .dll extension in assembly name in the pack:// uris. Otherwise you will spend a lot of time trying to understand why it does not work – Marek Feb 14 '13 at 11:33
19

To transform a classical library project to a WPF library project (in order to add UserControls, Windows, ResourcesDictionaries, etc.) you can add the following XML in the .csproj file in the first PropertyGroup Node :

<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

Full example :

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
    <PropertyGroup>
      <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
      <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
      <ProjectGuid>{50E8AAEA-5CED-46BE-AC9A-B7EEF9F5D4C9}</ProjectGuid>
      <OutputType>Library</OutputType>
      <AppDesignerFolder>Properties</AppDesignerFolder>
      <RootNamespace>WpfApplication2</RootNamespace>
      <AssemblyName>WpfApplication2</AssemblyName>
      <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
      <FileAlignment>512</FileAlignment>
      <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
      <WarningLevel>4</WarningLevel>
      <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
      <TargetFrameworkProfile />
    </PropertyGroup>
    <!-- ... -->    
default
  • 11,485
  • 9
  • 66
  • 102
nmariot
  • 465
  • 6
  • 15
17

@punker76's answer is great and helped me a lot, but it's worth adding that if you create an empty file and add a resource tag into it you should also go to file properties, set BuildAction to Resource, Copy To... to Do not copy and clear CustomTool property if it's set.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Chris W.
  • 366
  • 4
  • 15
13

In my opinion, the question is about adding a WPF Resource dictionary file to a Class Library project. The answer is that you can't do it for classic Class Library, but for WPF Application project, WPF Custom Control Library project or a WPF User Control Library. For these project types you can add a new Resource Dictionary (WPF), option which is available through adding new item to the project.

In my opinion the actual question title and question itself does not correspond to the accepted answer.

IAbstract
  • 19,551
  • 15
  • 98
  • 146
XMight
  • 1,991
  • 2
  • 20
  • 36
5

If you can't find the Resource Dictionary (WPF) file type when trying to create the dictionary, do this:

Add the following line to your project file (.csproj), into the first <PropertyGroup> element:

<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

Reload the project. Now you should have all the item types that can be found in a normal WPF project, including the Resource Dictionary (WPF).

GregorMohorko
  • 2,739
  • 2
  • 22
  • 33
1

Since i can't yet comment but i've used this answer twice now:

To add to nmariot's answer:


Tip 1

to reach the .csproj file from visual studio

right click project -> click 'unload project'

right click project [in unloaded state]-> click 'edit 'filename.csproj''

Tip 2

to avoid error warnings once resource dictionary has been added:

add reference to System.Xaml

Declan Taylor
  • 408
  • 6
  • 8
1

Yes. You can add a ResourceDictionary directly to your project.

When you want to use it, you can merge it into the XAML as needed by using MergedDictionaries to "merge" that standalone ResourceDictionary into the resources of the type (ie: the Window or UserControl).

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
0

I just came across the same problem in a project that was previously a Windows Application and then I turned into a Class Library (where I deleted the default App.xaml). I tried all the answers above and I managed to get my Visual Studio to let me create a Resource Dictionary from the Solution Explorer. In my case, my WPF UI was being launched from another so I made use of Application.Run(myMainWindow).

So far so good. But then I discovered that, as the resource dictionary was not being added through the App.xaml to the top of the resources hierarchy, I had to add a reference to the resourceDictionary in hundreds of .xaml files (or at least I couldn't make it work any other way using xaml). So I found a workaround for my case using code behind that may help someone.

The idea is just to convert the ResourceDictionary into a full class as explained in here or here and then force to add an instance of the RD to the top of the resources hierarchy in code behind before any xaml that uses these resources is created, emulating what App.xaml would have done. This way all the following WPF within the Application will inherit these styles and no further references are needed.

It has the advantage that if you change the location of your resourceDictionary, you don't have to change all paths (althougth you don't have to do it either if you refer to the RD as a full class as in here).

BUT if you use Application.Run(myMainWindow) directly, resources are not resolved on edition time, which is quite annoying, so I worked around it by launching a class derived from Application with an associated xaml and referencing the RD there as well (as the default App.xaml does). Note that both references to the RD are necessary, one for run time and the other one for edition time.

The App.xaml would look something like:

   <!-- App.xaml emulation-->
     <Application x:Class="myNamespace.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-myNamespace">    
        <Application.Resources>       
            <ResourceDictionary >
                <ResourceDictionary.MergedDictionaries>
                   <ResourceDictionary Source="MyStyles.xaml"/>
                </ResourceDictionary.MergedDictionaries>
             </ResourceDictionary>
        </Application.Resources>
    </Application>

and

   //App.xaml.cs
   using System.Windows;
   namespace myNamespace
   {
      public partial class App : Application
      {
        protected override void OnStartup(StartupEventArgs e) 
        {
            //Custom startup code here           
            base.OnStartup(e);
        }
      }
    }

and the ResourceDictionary like:

   <!-- MyStyles.xaml -->
     <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:myNamespace"
                    x:Class="myNamespace.MyStyles"
                    x:ClassModifier="public">

        <!-- All my styles in here -->

     </ResourceDictionary>

and

   //MyStyles.xaml.cs
   using System.Windows;
   namespace myNamespace
   {
     public partial class MyStyles: ResourceDictionary
     {
        public MyStyles()
        {
            InitializeComponent();
        }
     }
   }

And finally the GUI is launched with:

        public static void LaunchMainWindow()
        {                 
            App app = new App();

            //This sets the ResourceDict at the top of the hierarchy
            app.Resources.MergedDictionaries.Add(new MyStyles());
           
            app.Run(new myMainWindow());
        }

Amo Robb
  • 810
  • 5
  • 11