tags:

views:

143

answers:

3

I have an image being clipped like so:

<Image Width="45" Grid.Column="0" Source="{Binding Photo}" 
    <Image.Clip>
     <RectangleGeometry Rect="0,0,45,55" RadiusX="8" RadiusY="8" />
    </Image.Clip>
</Image>

How can I apply a drop shadow effect to it?

UPDATE:
As pointed out by Ray, the best solution is the one proposed by Anderson - having a wrapping border. Thanks Anderson.

+1  A: 

This should work

<Image Width="45" Grid.Column="0" Source="{Binding Photo}" 
    <Image.Clip>
        <RectangleGeometry Rect="0,0,45,55" RadiusX="8" RadiusY="8" />
    </Image.Clip>
    <Image.Effect>
        <DropShadowEffect Color="Black" BlurRadius="20" />
    </Image.Effect>
</Image>

I've not tried it in combination with Clip, though.

Update: That doesn't work (seems like a bug?)

I'd just do this:

<Border Grid.Column="0" >
     <Border.Effect>
          <DropShadowEffect />
     </Border.Effect>
    <Image Width="45" Source="{Binding Photo}" 
        <Image.Clip>
            <RectangleGeometry Rect="0,0,45,55" RadiusX="8" RadiusY="8" />
        </Image.Clip>
    </Image>
</Border>

Bit lame and you might have to tweak some of the widths to make sure they match exactly, but you get the idea.

Anderson Imes
Thanks Anderson, but this doesn't work because I am clipping the image, and the drop shadow is not included in the clip.
Gustavo Cavalcanti
That is very fascinating. Seems like an oversight. I'll update.
Anderson Imes
Anderson, it makes sense that it doesn't work the way you suggested. Suppose you have a 100x100 image and you clip to 50x50. The effect will be around the 100x100 image and since you're clipping a smaller place inside the image, it won't get the blur. Realize the clip is not resizing the picture at all.
Gustavo Cavalcanti
No I definitely get what is happening, but theory of least surprise would be that it would apply the effect post clip. In any case, applying the change to a border ought to work.
Anderson Imes
Sorry Anderson, applying the effect to the border doesn't work either. The border is around the image which still remains with the original size. Referring to my previous comment, you would have a border measuring 100x100 and a little rectangle inside it measuring only 50x50.
Gustavo Cavalcanti
That doesn't make a lot of sense. You have specified a width of "45" on your image. I'll have to work this out for myself, I think. Something doesn't seem right.
Anderson Imes
I was referring to my comment - original image 100x100 and clip 50x50.
Gustavo Cavalcanti
That's why I was saying you'd need to bind the width and height of the border to that of the image's ActualWidth / ActualHeight. I'll make a sample as soon as I get a chance.
Anderson Imes
Anderson, I tried binding the border width/height to the image's ActualWidth/Height but it doesn't know about those values and the border ends up with 0 for height and width.
Gustavo Cavalcanti
Anderson, I tried binding the border width/height to the image's ActualWidth/Height but it doesn't know about those values and the border ends up with 0 for height and width. Binding to Height.Width gets the values of the original image, and ActualHeight/ActualWidth gets 0.
Gustavo Cavalcanti
A: 

I guess the answer is that I need to use CroppedBitmap instead of Image.Clip:

<Image Width="45">
    <Image.Source>
     <CroppedBitmap Source="{Binding Photo}" SourceRect="0 0 45 55"/>
    </Image.Source>
    <Image.Effect>
     <DropShadowEffect/>
    </Image.Effect>
</Image>

and if I need the round corners I can surround the outer image with a border and use a ImageBrush:

<Border Width="45" Height="55" CornerRadius="10" >
    <Border.Background>
     <ImageBrush>
      <ImageBrush.ImageSource>
       <CroppedBitmap Source="profile.jpg" SourceRect="0 0 45 55"/>
      </ImageBrush.ImageSource>
     </ImageBrush>    
    </Border.Background>
</Border>

Please correct me if I am wrong or you can do it in a simpler manner. Thanks!

UPDATE: Apparently you cannot bind to CroppedBitmap's Source property!

Gustavo Cavalcanti
To be more precise, you can't access DataContext when binding to CroppedBitmap's Source property. Local bindings and bindings to specific source objects (Source=) are still possible, but not useful in this case. The reason you can't use DataContext or FindAncestor is that the CroppedBitmap doesn't have a DataContext property or the concept of a LogicalParent. FYI.
Ray Burns
Note: My comment was not intended to answer the original question, but merely to demystify the behavior you encountered and clarify a misunderstanding.
Ray Burns
Ray, can you please answer my question about this issue here?http://stackoverflow.com/questions/1711151/wpf-using-croppedbitmap-in-datatemplateThanks!
Gustavo Cavalcanti
+1  A: 

This will do the trick for you:

<Border>
  <Border.Effect>
    <DropShadowEffect />
  </Border.Effect>
  <Image Stretch="None" Source="{Binding Photo}" >
    <Image.Clip>
      <RectangleGeometry Rect="0,0,45,55" RadiusX="8" RadiusY="8"/>
    </Image.Clip>
  </Image>
</Border>

Which of course is your original idea, only with the DropShadowEffect applied to a wrapping Border. Because of the way bitmap effects work, they apply only to the visible part of what is contained.

Ray Burns
Thanks Ray. I double-checked and it works. I must give credit to Anderson.
Gustavo Cavalcanti
Yes, I see that my answer was identical to his edited answer except for the Stretch="None", which causes the Image to automatically have the correct size without having to hard-code the width.
Ray Burns