Как лучше всего повторно использовать блоки 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: Class к корневому элементу.

Или, может быть, я мог бы как-нибудь прочитать эти блоки с помощью 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, мне просто нужно изменить его в одном месте)


person Edward Tanguay    schedule 26.11.2009    source источник
comment
Кажется, то, что вы спрашиваете, похоже на главные страницы Asp.net. Не знаю, возможно ли это. Для вашего последнего образца TextBlock (изменение FontSize текстового блока PageTitle) разве не для этого предназначены стили?   -  person Robert Jeppesen    schedule 26.11.2009


Ответы (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}.

person Mart    schedule 26.11.2009
comment
Когда я это делаю, он сообщает мне: для корневого элемента ResourceDictionary требуется атрибут x: Class для поддержки обработчиков событий в файле XAML. Либо удалите обработчик событий для события MouseDown, либо добавьте атрибут x: Class к корневому элементу. когда я добавляю атрибут x: Class, я получаю такие ошибки: Отсутствует частичный модификатор при объявлении типа TestApp.Pages.BasePageManageItems; существует другое частичное объявление этого типа - person Edward Tanguay; 26.11.2009
comment
Правильно, у вас есть MouseDown события, которые нельзя связать во время компиляции, поскольку в словаре нет кода. Вам следует либо добавить обработчики событий во время выполнения, либо использовать команды: msdn.microsoft.com/ en-us / library / ms752308.aspx. - person Mart; 27.11.2009