3

DependencyProperties on UIElements do not support databinding (you get something like:

"Cannot find governing FrameworkElement..")

. If you try, you get an error because WPF can not resolve the DataContext. From what I know, you get binding support if you inherit FrameworkElement or Freezable, but In this case I can not simply change the base class. Is there any way to get the UIElement to support data binding?

I've tried to add the DataContext property to the UIElement class like this:

  FrameworkElement.DataContextProperty.AddOwner(typeof(Bitmap), new 
    FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

I also tried to bind by specifying "ElementName" in the binding expression, but I am still unable to resolve the parent DataContext (I thought that binding explicitly by ElementName would simply remove the need to resolve the DataContext).

This is the binding. The class in question is called "Bitmap".

<Utils:Bitmap Source="{Binding Path=Icon}" />
<TextBlock Grid.Row="1" Grid.ColumnSpan="3" MaxWidth="90" Text="{Binding Path=Name}" TextWrapping="Wrap" TextAlignment="Center"/>

The textblock binding works as expected, the first binding does not. The bound viewmodel has both properties (I bound to the Image class before and it worked).

The bitmap class can be found at this blog: http://blogs.msdn.com/b/dwayneneed/archive/2007/10/05/blurry-bitmaps.aspx

With some extended binding diagnostics, I get this output:

System.Windows.Data Warning: 65 : BindingExpression (hash=14926099): Framework mentor not found
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Icon; DataItem=null; target element is 'Bitmap' (HashCode=117163); target property is 'Source' (type 'BitmapSource')
System.Windows.Data Warning: 63 : BindingExpression (hash=6195855): Resolving source  (last chance)
System.Windows.Data Warning: 65 : BindingExpression (hash=6195855): Framework mentor not found
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Icon; DataItem=null; target element is 'Bitmap' (HashCode=55762700); target property is 'Source' (type 'BitmapSource')
System.Windows.Data Warning: 63 : BindingExpression (hash=48657561): Resolving source  (last chance)
System.Windows.Data Warning: 65 : BindingExpression (hash=48657561): Framework mentor not found
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Icon; DataItem=null; target element is 'Bitmap' (HashCode=35264868); target property is 'Source' (type 'BitmapSource')
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Marius
  • 9,208
  • 8
  • 50
  • 73
  • 4
    Of course UIElement supports binding, since it's a subclass of DependencyObject... The problem must be with your code, not with UIElement. Please show your XAML – Thomas Levesque May 20 '11 at 11:28
  • @Thomas - Data binding is supported only on `FrameworkElement's. See http://msdn.microsoft.com/en-us/library/ms743618.aspx. – Pavlo Glazkov May 20 '11 at 17:50
  • @Pavlo Glazkov, that's not true, I often use bindings on things that are not FrameworkElements. You can bind anything as long as it has dependency properties. But in some cases the DataContext is not inherited, so you need to specify the source explicitly. – Thomas Levesque May 22 '11 at 16:04
  • @Thomas - Source of the binding can be anything, but target must be a `FrameworkElement`. Consider this example: `` - here `Button` is a target of binding and it must be a `FrameworkElement` but the object that owns `SomeProperty` can be anything. If you still believe that it is not true, just try to set binding programmatically and you will quickly discover that `SetBinding` method exists only on `FrameworkElement's... – Pavlo Glazkov May 22 '11 at 19:36
  • @Pavlo Glazkov, `SetBinding` is declared on `FrameworkElement`, but it's just a shortcut for the static `BindingOperations.SetBinding`, which can be used on any `DependencyObject`. As I said before, I'm sure it works, I used it many times... – Thomas Levesque May 22 '11 at 21:12
  • @Thomas - OK, I've just checked and looks like you are right. You can set binding on any dependency object using `BindingOperations.SetBinding`, but you are limited what you can do to set the source of the binding. As you said, you have to specify the source explicitly. Neither `ElementName` binding nor binding to `DataContext` will work. – Pavlo Glazkov May 23 '11 at 07:51
  • @Pavlo Glazkov, actually it depends on whether the element is part of the visual or logical tree. See [this article](http://blogs.msdn.com/b/mikehillberg/archive/2008/05/23/of-logical-and-visual-trees-in-wpf.aspx) for details – Thomas Levesque May 23 '11 at 08:07
  • @Thomas - Updated my answer with two possible workarounds: specifying source explicitly and using `RelativeSource` for referring to an element in the visual tree. – Pavlo Glazkov May 23 '11 at 08:27

3 Answers3

7

You have to inherit FrameworkElement to use data binding. If you cannot change the base class, the only option you have is, as H.B. said, create an adapter that will be derived from FrameworkElement and will delegate all the functionality to an instance of the existing class derived from UIElement.

See http://msdn.microsoft.com/en-us/library/ms743618.aspx for more information on what the base framework classes (like UIElement and FrameworkElement) provide.

Update:

Even though MSDN (link above) says that the data binding support is introduced on the FrameworkElement level, it IS possible to set binding on any DependencyObject. The only thing is that in this case you cannot use DataContext as an implicit source for the binding and you cannot use ElementName for referring to the source.

What you can do is to set binding programmatically and specify source explicitly:

BindingOperations.SetBinding(MyBitmap, Bitmap.IconProperty, new Binding() { Source = this.DataContext /* Or any other source */, Path = new PropertyPath("Icon")});

OR you can use a little trick and use RelativeSource for referring to an element in the visual tree (in this case any parent FrameworkElement):

<Utils:Bitmap Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type FrameworkElement}}, Path=DataContext.Icon}" />
Pavlo Glazkov
  • 20,498
  • 3
  • 58
  • 71
  • `CollectionViewSource` supports DataContext even though it inherits from `DependencyObject`, so there is *some* way of getting around this requirement. A bit of digging has pointed me to an event called `InheritanceContextChanged`, but unfortunately it's `internal` to .Net... – Artfunkel Mar 24 '14 at 16:30
  • 1
    I believe RelativeSource doesn't work in that case because Bitmap won't be part of LogicalTree (only FrameworkElements and FrameworkContentElements are part of it) – user1121956 Nov 02 '15 at 01:36
5

You can use {Binding Source={x:Reference elementName}} instead of {Binding ElementName=elementName}.

Chadwick
  • 12,555
  • 7
  • 49
  • 66
haimb
  • 381
  • 3
  • 4
1

As noted you can bind on any object which inherits from DependencyObject, if you want a DataContext, I'd suggest you just make the class inherit from FrameworkElement. Even shapes like Rectangle do so, if you have some image-control it only makes sense to choose a higher level as the base-class.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • As stated in my question. I can not simply change the base class to "FrameworkElement" – Marius May 20 '11 at 11:41
  • Then just create an adapter which does. – H.B. May 20 '11 at 11:43
  • How can you state that you can bind to any object which inherits DependencyObject? If you bind to someting else than Freezables or FrameworkElement the framework complains that it can't resolve the DataContext. – Marius May 20 '11 at 11:44
  • One does not always bind to the DataContext, thus your general claim is simply wrong. – H.B. May 20 '11 at 12:45
  • Ok, but I also tried to bind to another control by using ElementName with no success. – Marius May 20 '11 at 12:54
  • Well, you cannot bind to ElementName either since the lookup process requires a governing framework element it seems, i think your only option is the `Source`, in which you can specify a static resource for example (you can add the object in your regular DataContext to a Resource-dictionary and then bind that way, of course if the DataContext is dynamic you'll have to update the dictionary). As i said before an adapter might be a good idea, also tell whoever made that class to never inherit from UIElement, according to MSDN there is only one class which does, and that is FrameworkElement. – H.B. May 20 '11 at 13:10