Пользовательский элемент управления WPF: TemplateBinding для обработки изображений

Я создаю пользовательский элемент управления WPF, a Button с Image и Text. Я добавил два свойства зависимости к управлению, ImagePath и Text, и шаблон управления (в Themes\Generic.xaml) является простой панелью стека, которая располагает изображение и текст горизонтально.

Text свойство хорошо работает. Но по некоторым причинам, демонстрационное изображение в моем тестовом проекте не появляется, когда я использую TemplateBinding к ImagePath свойство зависимости для получения его пути. Я протестировал изображение путем временной замены TemplateBinding в пользовательском элементе управления с путем к изображению, в этом случае это появляется.

Я надеюсь, что кто-то с большим опытом в этой области может смотреть и сказать мне, почему управление не работает как ожидалось.Спасибо за помощь.

Мое решение VS 2008 содержит один проект, CustomControlDemo. Проект содержит пользовательский элемент управления, TaskButton.cs, и главное окно, Window1.xaml, который я использую для тестирования управления. Мое тестовое изображение, calendar.png, расположено в папке Resources на корневом уровне проекта, и Generic.xaml расположен в папке Themes, также на корневом уровне проекта.

Вот код для моего пользовательского элемента управления (от TaskButton.cs):

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

namespace CustomControlDemo
{
    public class TaskButton : RadioButton
    {
        #region Fields

        // Dependency property backing variables
        public static readonly DependencyProperty ImagePathProperty;
        public static readonly DependencyProperty TextProperty;

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        static TaskButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TaskButton), new FrameworkPropertyMetadata(typeof(TaskButton)));

            // Initialize ImagePath dependency properties
            ImagePathProperty = DependencyProperty.Register("ImagePath", typeof(string), typeof(TaskButton), new UIPropertyMetadata(null));
            TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(TaskButton), new UIPropertyMetadata(null));
        }

        #endregion

        #region Dependency Property Wrappers

        /// <summary>
        /// The ImagePath dependency property.
        /// </summary>
        public string ImagePath
        {
            get { return (string)GetValue(ImagePathProperty); }
            set { SetValue(ImagePathProperty, value); }
        }

        /// <summary>
        /// The Text dependency property.
        /// </summary>
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        #endregion
    }
}

И вот шаблон управления (от 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:CustomControlDemo">


    <Style TargetType="{x:Type local:TaskButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:TaskButton}">
                    <StackPanel Height="Auto" Orientation="Horizontal">
                        <Image Source="{TemplateBinding ImagePath}"  Width="24" Height="24" Stretch="Fill"/>
                        <TextBlock Text="{TemplateBinding Text}"  HorizontalAlignment="Left" Foreground="{DynamicResource TaskButtonTextBrush}" FontWeight="Bold"  Margin="5,0,0,0" VerticalAlignment="Center" FontSize="12" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

И наконец, вот разметка Window1, которую я использую для тестирования управления:

<Window x:Class="CustomControlDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:customControl="clr-namespace:CustomControlDemo"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <customControl:TaskButton ImagePath="Resources\calendar.png" Text="Calendar" />
    </Grid>
</Window>

Какие-либо идеи, почему канал передачи изображения не работает? Еще раз спасибо.

7
задан Dave Clemmer 8 September 2011 в 16:29
поделиться

2 ответа

Изображение не принимает строку в качестве источника :) Вы можете увидеть это в intellisense. Вам необходимо выполнить привязку к ImageSource (или использовать IValueConverter для преобразования строки в ImageSource)

См. этот вопрос для получения некоторых советов о том, как выполнить это преобразование.

4
ответ дан 6 December 2019 в 12:51
поделиться

Я собираюсь оставить ответ cwap как принятый, потому что он технически правильный. Однако оказывается, что есть более простой способ решить эту проблему.

TemplateBindings не являются первоклассными объектами Binding. Они спроектированы так, чтобы быть легкими, поэтому они односторонние, и им не хватает некоторых функций других объектов Binding. В частности, они не поддерживают преобразователи известных типов, связанные с целью. См. MacDonald, Pro WPF в C # 2008 , стр. 872. Вот почему cwap правильно реагирует на то, что мне, вероятно, потребуется создать преобразователь типов и ссылаться на него специально в шаблоне элемента управления для моей пользовательской кнопки.

Но мне не нужно использовать TemplateBinding для привязки шаблона элемента управления к ImagePath моего настраиваемого элемента управления. Я могу использовать простой старый объект Binding. Вот измененная разметка для моего шаблона настраиваемого элемента управления:

<!-- Task Button Default Control Template-->
<Style TargetType="{x:Type local:TaskButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TaskButton}">
                <StackPanel Height="Auto" Orientation="Horizontal">
                    <Image Source="{Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}}" Width="24" Height="24" Stretch="Fill" Margin="10,0,0,0" />
                    <TextBlock Text="{TemplateBinding Text}"  HorizontalAlignment="Left" Foreground="{TemplateBinding Foreground}" FontWeight="Bold"  Margin="5,0,10,0" VerticalAlignment="Center" FontSize="12" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Если вы посмотрите на ImageControl в шаблоне, вы увидите изменение. Обратите внимание на свойство RelativeSource в том же объекте. Установка этого свойства на = {RelativeSource TemplatedParent} - это то, что позволяет мне ввести относительный путь в моем экземпляре Window1 для TaskButton и правильно разрешить его в настраиваемом элементе управления.

Поэтому я рекомендую другим, исследующим этот поток, пропустить преобразователь значений и просто переключитесь с TemplateBinding на Binding для свойства Image.

Спасибо также Марко Чжоу, который предоставил этот ответ на аналогичный вопрос на форуме MSDN WPF.

Обратите внимание на свойство RelativeSource в том же объекте. Установка этого свойства на = {RelativeSource TemplatedParent} - это то, что позволяет мне ввести относительный путь в моем экземпляре Window1 для TaskButton и правильно разрешить его в настраиваемом элементе управления.

Поэтому я рекомендую другим, исследующим этот поток, пропустить преобразователь значений и просто переключитесь с TemplateBinding на Binding для свойства Image.

Спасибо также Марко Чжоу, который предоставил этот ответ на аналогичный вопрос на форуме MSDN WPF.

Обратите внимание на свойство RelativeSource в том же объекте. Установка этого свойства на = {RelativeSource TemplatedParent} - это то, что позволяет мне ввести относительный путь в моем экземпляре Window1 для TaskButton и правильно разрешить его в настраиваемом элементе управления.

Поэтому я рекомендую другим, исследующим этот поток, пропустить преобразователь значений и просто переключитесь с TemplateBinding на Binding для свойства Image.

Спасибо также Марко Чжоу, который предоставил этот ответ на аналогичный вопрос на форуме MSDN WPF.

10
ответ дан 6 December 2019 в 12:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: