Bind an ImageBrush to a template with a DependencyProperty

て烟熏妆下的殇ゞ 提交于 2019-12-14 04:25:41

问题


I'm trying to create a special button that colors an image based on Foreground color from the system. The solution seems to be in using the image as opacity mask to get the color and it works when I set the image directly like this:

<Grid>
  <Rectangle x:Name="ImageForeground" Height="48" Width="48" 
    Fill="{StaticResource PhoneForegroundBrush}" >
    <Rectangle.OpacityMask>
      <ImageBrush Stretch="Fill" ImageSource="/icons/play.png"/>
    </Rectangle.OpacityMask>
  </Rectangle>
</Grid>

But as soon as I try template this with a DependencyProperty for the image lite this:

public static readonly DependencyProperty ImageProperty  =
  DependencyProperty.Register("Image", typeof(ImageSource), 
                              typeof(RButton), null);  

And then in the XAML like this:

<Grid>
  <Rectangle x:Name="ImageForeground" Height="48" Width="48" 
    Fill="{TemplateBinding Foreground}" >
    <Rectangle.OpacityMask>
      <ImageBrush Stretch="Fill" ImageSource="{TemplateBinding Image}"/>
    </Rectangle.OpacityMask>
  </Rectangle>
</Grid>

I get an error saying:

object of type 'System.Windows.CustomDependencyProperty' 
  cannot be converted to type 'System.Windows.DependencyProperty'

The ImageProperty is ok, as I tested binding it to an image instead like this

<Image Source="{TemplateBinding Image}" Width="48" Height="48" />

Any ideas? My hunch says its in how I define my DependecyProperty, but I don't know how to move forward.


回答1:


The ImageBrush doesn't inherit from FrameworkElement so it can't be TemplateBound or Data Bound.




回答2:


I tried to replicate your problem in a test project based on the XAML you've given and have to admit that I haven't run into the problem that you describe. If you could provide the code for the RButton and some context as to how the control is used I might have more luck (or lack of!).

There was a great blog post All about Dependency Properties in Silverlight for WP7 posted today that you might find useful.

UPDATE: I just read this perfectly matched article that explains the problem fully and gives a solution. Basically, ImageBrush isn't a FrameworkElement, so you can't use the TemplateBinding with it.




回答3:


I marked It as answer although it wasn't the full answer. To get it all working I had to do some tweaking as I can't use a Converter in a TemplateBinding, sigh... anyway. Here is the code that solved it for me together with the converter in the article that Derek pointed out.

So to bind my Image DependencyProperty as an image brush in my Template I have to do this...

<Grid>
  <Grid.Resources>
    <controls:ImageBrushConverter x:Key="brushConverter"/>
  </Grid.Resources>
  <Rectangle 
    x:Name="ImageForeground"
    Height="48"
    Width="48" 
    Fill="{TemplateBinding Foreground}" 
        DataContext="{TemplateBinding Image}"
        OpacityMask="{Binding Converter={StaticResource brushConverter}}">
  </Rectangle>
</Grid> 

Not obvious but it did the trick, this has solved a lot for me. Thanks for the help




回答4:


You can use a RelativeSource TemplatedParent binding instead of TemplateBinding. This is basically the same thing, but it will work in those odd cases where the TemplateBinding does not.

<ImageBrush
    ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Image}" />



回答5:


Another approach but without need of converter

<Grid>
<Rectangle x:Name="ImageForeground" DataContext="{TemplateBinding Image}" Height="48" Width="48" 
        Fill="{TemplateBinding Foreground}" >
    <Rectangle.OpacityMask>
        <ImageBrush Stretch="Fill" ImageSource="{Binding DataContext , RelativeSource={RelativeSource AncestorType=Rectangle}}"/>
    </Rectangle.OpacityMask>
</Rectangle>

//Or

<Rectangle DataContext="{TemplateBinding IconVisual}" x:Name="Icon" RadiusX="2" RadiusY="2" StrokeThickness="1" Margin="{TemplateBinding Padding}"  Fill="{TemplateBinding Foreground}" Stroke="{TemplateBinding Foreground}" >
                                <Rectangle.OpacityMask>
                                    <VisualBrush Visual="{Binding DataContext , RelativeSource={RelativeSource AncestorType=Rectangle}}"  Stretch="Uniform" />
                                </Rectangle.OpacityMask>
                            </Rectangle>



回答6:


Or if you are author of control then OnApplyTemplate, find the visual brush in template and set its value.

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    VisualBrush oVBrushBack = (VisualBrush)this.Template.FindName("rectVisual", this);

    oVBrushBack.Visual = this.IconVisual;
}


来源:https://stackoverflow.com/questions/4861659/bind-an-imagebrush-to-a-template-with-a-dependencyproperty

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!