WPF 自定义控件 : TemplateBinding to Image

标签 wpf image wpf-controls controltemplate templatebinding

我正在创建一个 WPF 自定义控件,一个 ButtonImageText .我在控件中添加了两个依赖属性 ImagePathText ,并且控件模板(在 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>

任何想法为什么图像路径不起作用?再次感谢。

最佳答案

我将把 cwap 的答案作为接受的答案,因为它在技术上是正确的。然而,事实证明有一种更简单的方法可以解决这个问题。

TemplateBindings 不是一流的 Binding 对象。它们被设计为轻量级的,因此它们是单向的,并且它们缺少其他 Binding 对象的某些功能。最值得注意的是,它们不支持与目标关联的已知类型转换器。见麦克唐纳, C# 2008 中的专业 WPF ,页。 872. 这就是为什么 cwap 正确响应我可能需要创建一个类型转换器并在我的自定义按钮的控件模板中专门引用它的原因。

但我不必使用 TemplateBinding 将控件模板绑定(bind)到自定义控件的 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} 可以让我在 TaskButton 的 Window1 实例中输入相对路径,并在自定义控件中正确解析它。

因此,我对其他研究此线程的人的建议是跳过值转换器,只需从 TemplateBinding 切换到 Image 属性的 Binding。

还要感谢 Marco Zhou,他提供了 this answer到 MSDN WPF 论坛中的类似问题。

关于WPF 自定义控件 : TemplateBinding to Image,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1935919/

相关文章:

c# - 如何以编程方式将 RibbonTab 添加到 WPF 功能区(2010 年 10 月版本)?

c# - 新的WPF项目将无法编译-抛出错误 “The name ' InitializeComponent'在当前上下文中不存在”

WPF:打印分页数据网格的最佳方法

c# - 如何将多个处理程序添加到 XAML 中的附加事件?

python - 使用 Selenium 通过 MacOS 窗口上传图像

JavaFX 图像性能优化

WPF 列表框向下滚动

jquery - rails/CSS : How do I make a gallery of images of different widths?

c# - 如何在另一个线程上渲染视觉对象

wpf-controls - 如何让我的 WPF 滚动查看器使用缩放功能?