【问题标题】:WPF Custom Control: TemplateBinding to ImageWPF 自定义控件:模板绑定到图像
【发布时间】:2010-12-28 11:59:55
【问题描述】:

我正在创建一个 WPF 自定义控件,一个带有 ImageTextButton。我在控件中添加了两个依赖属性ImagePathText,控件模板(在 Themes\Generic.xaml 中)是一个简单的堆栈面板,可以水平排列图像和文本。

Text 属性工作正常。但是由于某种原因,当我使用TemplateBindingImagePath 依赖属性来获取它的路径时,我的测试项目中的示例图像没有出现。我已经通过将自定义控件中的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>

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

【问题讨论】:

    标签: wpf image wpf-controls controltemplate templatebinding


    【解决方案1】:

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

    TemplateBindings 不是一流的 Binding 对象。它们被设计为轻量级的,因此它们是单向的,并且它们缺少其他 Binding 对象的某些功能。最值得注意的是,它们不支持与目标关联的已知类型转换器。请参阅 MacDonald,C# 2008 中的 Pro WPF,第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 论坛中的类似问题提供了 this answer

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

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

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

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

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

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

        【讨论】:

          【解决方案4】:

          简单的方法(经过测试) 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}}"/>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-07-03
            • 1970-01-01
            • 2015-09-07
            • 2012-08-18
            • 1970-01-01
            • 2015-06-03
            • 1970-01-01
            相关资源
            最近更新 更多