7

我正在创建一个 WPF 自定义控件,一个Button带有Imageand的Text。我在控件中添加了两个依赖属性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>

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

4

4 回答 4

10

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

TemplateBindings 不是一流的 Binding 对象。它们被设计为轻量级的,因此它们是单向的,并且它们缺少其他 Binding 对象的某些功能。最值得注意的是,它们不支持与目标关联的已知类型转换器。请参阅 MacDonald,C# 2008 中的 Pro WPF,p。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} 可以让我在 TaskButton 的 Window1 实例中输入相对路径,并在自定义控件中正确解析它。

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

还要感谢 Marco Zhou,他在 MSDN WPF 论坛中为类似问题提供了这个答案。

于 2009-12-20T20:16:52.620 回答
4

图像不将字符串作为源:) 您可以在智能感知中看到这一点。您需要在 ImageSource 上绑定(或使用 IValueConverter 将字符串转换为 ImageSource)

有关如何进行此转换的一些提示,请参阅此问题。

于 2009-12-20T14:16:01.683 回答
2

实际上,这些答案都不是正确的。

{TemplateBinding ImagePath}只不过是一个快捷方式,{Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}}因此几乎完全相同。

此外,如果您为其提供一个字符串,ImagePath它将正确解析为一个,ImageSource尽管您在应用程序性能方面受到了影响。真正的问题与ImagePath="Resources\calendar.png"xaml 中为测试提供的相对和绝对图像路径有关。这提示编译器认为提供的路径是绝对的,因为在定义路径时使用 \ 而不是 /。

绑定的长格式有效而快捷方式无效的原因是它为编译器提供了线索,即提供的图像的源 (Resources\calendar.png) 是相对路径而不是绝对路径,因此图像找到并且绑定有效。如果您调试绑定,您将看到快捷方式尝试将提供的字符串解析为图像源,但找不到文件“Resources\calendar.png”如果您提供图像的完整 URI 即"C:\...\Resources\calendar.png"或相应的混合表示法"/application;component/Resources/calendar.png"then将找到图像并解决绑定。

当您尝试从外部源引用图像而不是那些作为资源编译到最终编译中的图像时,这一点变得非常重要。

于 2011-12-05T23:12:24.613 回答
0

简单的方法(经过测试) 1-让你的 valueConverter 像这样

  public class objectToImageSourceConverter:IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {

            string packUri =value.ToString();
            ImageSource Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;
            return Source;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

2-将您的图像源绑定到父级的字符串属性(我使用“标记”属性),如下所示 xaml:

<Image HorizontalAlignment="Right"  Height="Auto" Margin="0,11.75,5.5,10.75" VerticalAlignment="Stretch" Width="40.997" Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
于 2015-08-18T18:16:49.517 回答