Каков наилучший способ повторного использования блоков XAML?

У меня есть много пользовательских элементов управления, например:

PageManageCustomers.xaml.cs:

public partial class PageManageCustomers : BasePage
{
 ...
}

которые наследуют от:

PageBase.cs:

public class BasePage : UserControl, INotifyPropertyChanged
{
 ...
}

Поскольку PageBase.cs имеет отсутствующий файл XAML, я должен поместить XAML, на который он ссылается, в каждый элементов управления пользователя которые наследуют его, например следующий блок повторяется в каждом файле XAML каждого элемента управления, который наследует PageBase:

<DataTemplate x:Key="manageAreaCellTemplate">
    <StackPanel Orientation="Horizontal">
        <TextBlock Style="{DynamicResource ManageLinkStyle}"
    Tag="{Binding Id}" Text="Delete" MouseDown="System_Delete_Click"/>
        <TextBlock Text=" "/>
        <TextBlock Style="{DynamicResource ManageLinkStyle}"
           Tag="{Binding Id}" Text="Edit" MouseDown="System_Edit_Click"/>
    </StackPanel>
</DataTemplate>

Я пытаюсь поместить этот блок в файл ресурса, но не могу получить синтаксис правильно, он говорит:

'Корневой элемент ResourceDictionary' требует атрибут x: Class поддержка обработчиков событий в XAML файл. Либо удалите обработчик событий для события MouseDown или добавьте x: атрибут класса к корневому элементу.

Или, может быть, я мог бы прочитать эти блоки с помощью XamlReader `как-то?

Как я могу поместить этот повторяющийся блок кода в одном месте, чтобы он не повторялся в каждом файле XAML, который наследует BagePage?

Вот воспроизводимый пример этой проблемы:

Window1.xaml:

<Window x:Class="TestXamlPage8283.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel x:Name="MainContent"/>
</Window>

Window1.xaml.cs:

using System.Windows;

namespace TestXamlPage8283
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            Page1 page1 = new Page1();
            MainContent.Children.Add(page1);

            Page2 page2 = new Page2();
            MainContent.Children.Add(page2);
        }
    }
}

Page1.xaml:

<local:BasePage x:Class="TestXamlPage8283.Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestXamlPage8283"
    Height="40" Width="300">
    <StackPanel>
        <TextBlock Text="{Binding PageTitle}"
                   FontSize="14"
                   FontWeight="Bold"/>
        <TextBlock Text="This is XAML that is specific to page one." />
    </StackPanel>
</local:BasePage>

Page1.xaml.cs:

namespace TestXamlPage8283
{
    public partial class Page1 : BasePage
    {
        public Page1()
        {
            InitializeComponent();
            PageTitle = "Page One";
        }
    }
}

Page2.xaml:

<local:BasePage x:Class="TestXamlPage8283.Page2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestXamlPage8283"
    Height="40" Width="300">
    <StackPanel>
        <TextBlock Text="{Binding PageTitle}"
                   FontSize="14"
                   FontWeight="Bold"/>
        <TextBlock Text="This is XAML that is specific to page two." />
    </StackPanel>
</local:BasePage>

Page2.xaml.cs:

namespace TestXamlPage8283
{
    public partial class Page2 : BasePage
    {
        public Page2()
        {
            InitializeComponent();
            PageTitle = "Page Two";
        }
    }
}

BasePage.cs:

using System.Windows.Controls;
using System.ComponentModel;

namespace TestXamlPage8283
{
    public class BasePage : UserControl, INotifyPropertyChanged
    {
        #region ViewModelProperty: PageTitle
        private string _pageTitle;
        public string PageTitle
        {
            get
            {
                return _pageTitle;
            }

            set
            {
                _pageTitle = value;
                OnPropertyChanged("PageTitle");
            }
        }
        #endregion

        public BasePage()
        {
            DataContext = this;
        }

        #region INotifiedProperty Block
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

Как взять этот блок

<TextBlock Text="{Binding PageTitle}"
           FontSize="14"
           FontWeight="Bold"/>

из Page1.xaml и Page2.xaml и поместите его в одно место, чтобы я мог ссылаться на него из Page1.xaml и Page2.xaml? (так что, когда я хочу изменить FontSize = 14 до FontSize = 16, я просто должен изменить его в одном месте)

Ответ 1

Используйте ресурсные словари - добавьте файл MyDictionary.xaml в свой проект, установив для его действия "Действие" значение "Страница":

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataTemplate x:Key="manageAreaCellTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Style="{DynamicResource ManageLinkStyle}"
              Tag="{Binding Id}" Text="Delete" MouseDown="System_Delete_Click"/>
            <TextBlock Text=" "/>
            <TextBlock Style="{DynamicResource ManageLinkStyle}"
              Tag="{Binding Id}" Text="Edit" MouseDown="System_Edit_Click"/>
        </StackPanel>
    </DataTemplate>
</ResourceDictionary>

Затем в других файлах XAML вы ссылаетесь на него с помощью:

<ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="MyDictionary.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    ... some other local resources ...
</ResourceDictionary>

и обратитесь к вашему ресурсу как Template={StaticResource manageAreaCellTemplate}.