WPF инкапсулирует прямоугольник с помощью StaticResource в качестве заливки для CustomControl в WPF

Я использую ModernUIIcons, которые поставляются с MahApps.Metro в файле Xaml как StaticResources. Поместить его в мой пользовательский интерфейс очень просто, вот так:

<Rectangle  Width="19" 
            Height="19">
   <Rectangle.Fill>
      <VisualBrush Visual="{StaticResource appbar_database}" />
   </Rectangle.Fill>
</Rectangle>

Я хочу инкапсулировать всю логику прямоугольника в CustomControl, чтобы сделать что-то вроде следующего:

<cc:MenuItemIcon Source="{StaticResource appbar_page}"/>

Вот что у меня получилось:

В одном проекте в виде библиотеки Themes / Generic.xaml:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AMIGEDM.CustomControls.Menu">

<Style TargetType="{x:Type local:MenuItemIcon}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MenuItemIcon}">
                <Rectangle  Width="19" 
                            Height="19">
                    <Rectangle.Fill>
                        <VisualBrush Visual="{TemplateBinding Source}" />
                    </Rectangle.Fill>
                </Rectangle>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
</ResourceDictionary>

И в файле CS

namespace AMIGEDM.CustomControls.Menu
{
   public class MenuItemIcon : Control
{
   static MenuItemIcon()
   {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuItemIcon), new  FrameworkPropertyMetadata(typeof(MenuItemIcon)));
   }

   public static readonly DependencyProperty SourceProperty =
      DependencyProperty.Register("Source", typeof(Visual), typeof(MenuItemIcon));

   public Visual Source
   {
      get { return (Visual)GetValue(SourceProperty); }
      set { SetValue(SourceProperty, value); }
   }
  }
}

Все компилируется как шелк, поэтому я перехожу в свой проект TestDummy.

<Window x:Class="AMIGEDM.TestDummy.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    xmlns:cc="clr-namespace:AMIGEDM.CustomControls.Menu;assembly=AMIGEDM.CustomControls">
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/AMIGEDM.TestDummy;component/Resources/Icons.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/AMIGEDM.CustomControls;component/Themes/Generic.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>
<Grid>
    <Menu IsMainMenu="True" SnapsToDevicePixels="True">
        <MenuItem Header="_Open">
            <MenuItem Header="_File">
                <MenuItem.Icon>
                    <cc:MenuItemIcon Source="{StaticResource appbar_page}"/>
                </MenuItem.Icon>
            </MenuItem>
            <MenuItem Header="_File">
                <MenuItem.Icon>
                    <Rectangle  Width="19" 
                            Height="19">
                        <Rectangle.Fill>
                            <VisualBrush Visual="{StaticResource appbar_database}" />
                        </Rectangle.Fill>
                    </Rectangle>
                </MenuItem.Icon>
            </MenuItem>
        </MenuItem>
    </Menu>
</Grid>

The Library puts the Icon using the Rectangle, Rectangle Fill and VisualBrush, but when I try to use the CustomControl it shows nothing

Как вы видите, значок отображается с использованием всего прямоугольника, но не с моим настраиваемым элементом управления


person Claudiordgz    schedule 22.08.2013    source источник
comment
У меня нет VS, чтобы проверить это, но попробуйте следующее: ‹MenuItem Header = _File Icon = {StaticResource appbar_page} /›   -  person Eyjafjallajokull    schedule 23.08.2013
comment
@Eyjafjallajokull, спасибо, но мне нужно изменить размер иконок, поэтому я не использую их напрямую   -  person Claudiordgz    schedule 23.08.2013
comment
Source = {StaticResource appbar_page} - это прямоугольник, а Visual = {StaticResource appbar_database} - это значок, если я правильно понял из вашего XAML. Я имею в виду дать ключ прямоугольнику и установить его как значок пункта меню вместо использования настраиваемого элемента управления - как вы это делаете во втором элементе меню, который отображается правильно, но использует ресурс.   -  person Eyjafjallajokull    schedule 23.08.2013


Ответы (1)


Весь код выглядит нормально, за исключением стиля MenuItemIcon. Цитата о TemplateBinding из книги Адама Натана:

TemplateBinding не работает вне шаблона или вне его свойства VisualTree, поэтому вы даже не можете использовать TemplateBinding внутри триггера шаблона. Более того, TemplateBinding не работает при применении к Freezable (в основном по искусственным причинам).

И цитата из MSDN о VisualBrush:

Возможности Freezable: поскольку он наследуется от класса Freezable, класс VisualBrush предоставляет несколько специальных функций: объекты VisualBrush могут быть объявлены как ресурсы и совместно использоваться несколькими объектами.

Поэтому вместо:

<VisualBrush Visual="{TemplateBinding Source}" />

Используйте конструкцию {RelativeSource TemplatedParent} и Path, равную свойству зависимости, значение которого вы хотите получить:

<Style TargetType="{x:Type local:MenuItemIcon}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MenuItemIcon}">
                <Rectangle Width="22" Height="22">
                    <Rectangle.Fill>
                        <VisualBrush Visual="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Source}" />                                
                    </Rectangle.Fill>
                </Rectangle>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
person Anatoliy Nikolaev    schedule 23.08.2013