Создание WPF библиотеки окон, контролов, ресурсов и стилей.



Часто возникает ситуация когда несколько WPF приложений используют одни и те же окна, контролы, стили и ресурсы. Самым лучшим решением является - вынести все совместно используемые компоненты в отдельную DLL сборку. Но на практике оказывается все не так просто. Эти осложнения обусловлены тем, что Visual Studio 2008 не позволяет добавлять, некоторые элементы WPF, такие например как ResourceDictionary и Window, в ClassLibrary проект. Далее я  расскажу, как создавать WPF библиотеки на основе ClassLibrary проекта.

Создадим Solution и добавим туда 3 проекта:

  • WpfApplication1 - WPF Application
  • WpfApplication2 - WPF Application
  • WpfLibrary - Class Library

Добавим Resource Dictionary в каждый из созданных проектов. Назовем их везде одинаково - ResourceDictionary.

Примечание: Visual Studio 2008 не позволяет добавлять некоторые элементы WPF приложения в Class Library проект. Поэтому сначала следует создать необходимый элемент в проекте WPF Application, а потом перенести его в проект Class Library. Причем, после переноса файлов необходимо изменить значение атрибута Build Action на Page.

Добавим ресурсы и стили в ResourceDictionary.

WpfApplication1:

ResourceDictionary.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:s="clr-namespace:System;assembly=mscorlib">

    <s:String x:Key="WpfApplication1String">Строка из WpfApplication1</s:String>

    <Style x:Key="WpfApplication1Style"
           TargetType="TextBlock">
        <Setter Property="Background" Value="Blue" />
    </Style>

</ResourceDictionary>

WpfApplication2:

ResourceDictionary.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:s="clr-namespace:System;assembly=mscorlib">

    <s:String x:Key="WpfApplication2String">Строка из WpfApplication2</s:String>

    <Style x:Key="WpfApplication2Style"
           TargetType="TextBlock">
        <Setter Property="Background" Value="Green" />
    </Style>

</ResourceDictionary>

WpfLibrary:

ResourceDictionary.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:s="clr-namespace:System;assembly=mscorlib">
    
    <s:String x:Key="WpfLibraryString">Строка из WpfLibrary</s:String>    
    
    <Style x:Key="WpfLibraryStyle"
           TargetType="TextBlock">
        <Setter Property="Background" Value="Red" />
    </Style>
    
</ResourceDictionary>

Сделаем созданные Resource Dictionary, видимыми во всем приложении для WpfApplication1 и WpfApplication2. Для этого включим созданные Resource Dictionary в App.xaml.

WpfApplication1:

App.xaml:

<Application x:Class="WpfApplication1.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="ResourceDictionary.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/WpfLibrary;component/ResourceDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

WpfApplication2:

App.xaml:

<Application x:Class="WpfApplication2.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="ResourceDictionary.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/WpfLibrary;component/ResourceDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Создадим User Control (WPF) в WpfLibrary и назовем его UserControl1. И используем в этом контроле стили и ресурсы, определенные в ResourceDictionary в проекте WpfLibrary.

WpfLibrary:

UserControl1.xaml:

<UserControl x:Class="WpfLibrary.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Height="100" Width="200">
    <TextBlock Style="{StaticResource WpfLibraryStyle}"  
               Text="{StaticResource WpfLibraryString}"/>
</UserControl>

Далее, создадим Window в WpfLibrary с названием CustomWindow.

WpfLibrary:

CustomWindow.xaml:

<Window x:Class="WpfLibrary.CustomWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WpfLibrary="clr-namespace:WpfLibrary"
        Title="Custom Window"
        SizeToContent="WidthAndHeight">
    <WpfLibrary:UserControl1/>
</Window>

Теперь изменим главные окна Window1 приложений WpfApplication1 и WpfApplication2 так, чтобы они использовали окно, контрол, стиль и ресурс из WpfLibrary, наряду со стилями и ресурсами, определенными в самом WPF приложении.

 WpfApplication1:

 Window1.xaml:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WpfLibrary="clr-namespace:WpfLibrary;assembly=WpfLibrary"
        Title="WpfApplication1" 
        Height="320" Width="300">
    
    <StackPanel Orientation="Vertical">
        
        <TextBlock Style="{StaticResource WpfApplication1Style}"  
                   Text="{StaticResource WpfApplication1String}"
                   HorizontalAlignment="Center"
                   Height="80" Width="200"/>
        
        <TextBlock Style="{StaticResource WpfLibraryStyle}"  
                   Text="{StaticResource WpfLibraryString}"
                   HorizontalAlignment="Center"
                   Height="80" Width="200"/>
        
        <WpfLibrary:UserControl1 HorizontalAlignment="Center"
                                 Height="80" Width="200" />
        
        <Button Content="Show Window"
                Click="Button_Click" 
                HorizontalAlignment="Center"
                Height="30" Width="100"/>
        
    </StackPanel>
        
</Window>

  Window1.xaml.cs:

using System.Windows;
using WpfLibrary;

namespace WpfApplication1
{
    public partial class Window1
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var wnd = new CustomWindow { Owner = this };
            wnd.ShowDialog();
        }
    }
}

 WpfApplication2:

 Window1.xaml:

<Window x:Class="WpfApplication2.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WpfLibrary="clr-namespace:WpfLibrary;assembly=WpfLibrary"
        Title="WpfApplication2" 
        Height="320" Width="300">

    <StackPanel Orientation="Vertical">

        <TextBlock Style="{StaticResource WpfApplication2Style}"  
                   Text="{StaticResource WpfApplication2String}"
                   HorizontalAlignment="Center"
                   Height="80" Width="200"/>

        <TextBlock Style="{StaticResource WpfLibraryStyle}"  
                   Text="{StaticResource WpfLibraryString}"
                   HorizontalAlignment="Center"
                   Height="80" Width="200"/>
        
        <WpfLibrary:UserControl1 HorizontalAlignment="Center"
                                 Height="80" Width="200" />

        <Button Content="Show Window"
                Click="Button_Click" 
                HorizontalAlignment="Center"
                Height="30" Width="100"/>

    </StackPanel>
    
</Window>

  Window1.xaml.cs:

using System.Windows;
using WpfLibrary;

namespace WpfApplication2
{
    public partial class Window1
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var wnd = new CustomWindow { Owner = this };
            wnd.ShowDialog();
        }
    }
}

Запустим приложения

Видим, что контрол, окно, ресурс и стиль из WpfLibrary используются в двух разных приложениях WPF.

Ссылка на скачивание Solution: WPFLibrary.zip

.NET , WPF


Комментировать

Комментарии

Spaniard

31.07.2009 14:08

Запомню.
Скачаю и проанализирую. Спасибо, это интересно, Андрей-доно =)

notacat

06.05.2010 1:35

Зачем так мучиться? Проще сразу создать WPF User Control Library или WPF Custom Control Library. Они в мастере создания проектов находятся в Visual C# - Windows.
Наверное и готовый ClassLibrary проект можно подредактировать, чтобы студия начала с ним нормально работать.