Damascus
Damascus

Reputation: 6651

Binding to a property not specified in the interface bound

The title is a bit blur here, I didn't find a way to say it more clearly.

Let's take a simple and very clear example of my situation:

First: I have a custom control, FooControl , with a DependencyProperty of type IFoo. The control is supposed to display IFoo objects in a DataGrid

Please note that, of course, the real object is not just about displaying some values, I could have used just a DataGrid for this matter ;)

public class FooControl : DataGrid
{
        /// <summary>
        /// Foo!
        /// </summary>
        public static readonly DependencyProperty FooProperty =
            DependencyProperty.Register("Foo",
                                        typeof(IFoo),
                                        typeof(FooControl),
                                        new PropertyMetadata(FooChanged));

Second: I have an IFoo interface

public interface IFoo
{
    IList<double> Values { get; set; }
}

Third: I have a Foo object, implementing IFoo

public class Foo : IFoo
{
    public IList<double> Values { get; set; }
}

And now, I want an ObservableFoo, for binding updates purpose, here it is:

public class ObservableFoo : Foo, INotifyCollectionChanged
{
    public ObservableCollection<double> ObservableValues {get; set; }
}

Now, THE PROBLEM:

I usually have my FooControls bound to objects of type Foo, which are "strict" implementations of the IFoo interface. Now, I also need to have three FooControls which should be bound to objects of type ObservableFoo (which obviously are IFoo, but also add a property not specified in the interface, ie ObservableValues )

in the FooControl class, I manually set a binding to the values to be displayed:

    /// <summary>
    /// Sets the binding on foo values
    /// </summary>
    /// <param name="propertyPath">Binding path</param>
    public void SetValuesBinding(string propertyPath)
    {
        // Binding for foovalues
        Binding fooBinding = new Binding(propertyPath);
        fooBinding.Converter = new FooConverter();
        fooBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        fooBinding.RelativeSource = new RelativeSource(RelativeSourceMode.Self);
        fooBinding.Mode = BindingMode.TwoWay;

        this.SetBinding(FooControl.ItemsSourceProperty, fooBinding);
    }

When propertyPath is Foo.Values , it works fine, updating the binding's target will call the PropertyChangedHandler I defined for ItemsSource

When propertyPath is Foo.ObservableValues, updating the binding won't call the PropertyChangedHandler I defined. However, there is no Binding error displayed on the output window!

In my comprehension of the problem, it means that:

How could I manage to update the binding to ObservableValues ?

I hope I made it clear enough for you guys. Please feel free to ask any question if you need me to clarify

Upvotes: 0

Views: 122

Answers (3)

Damascus
Damascus

Reputation: 6651

Okay, I finally went for a workaround.

I Added a property to the FooControl :

    /// <summary>
    /// The values displayed
    /// </summary>
    public System.Collections.IEnumerable ValuesToDisplay
    {
        get
        {
            if (this.Foo is ObservableFoo)
            {
                return (this.Foo as ObservableFoo).ObservableValues;
            }
            else if (this.Foo == null)
            {
                return null;
            }
            else
            {
                return this.Foo.Values;
            }
        }
    }

And I bind the embedded Datagrid's ItemSource to this property (using a RelativeSource pointing to itself) and... It works fine.

But still, this made me learn something: binding does not resolve types at runtime, it will just take the specified type apparently!

Upvotes: 0

Rachel
Rachel

Reputation: 132618

I think the issue is with your binding.

You're binding to RelativeSource Self, which means your binding is reading FooControl.Foo.ObservableValues, and since Foo is defined as an IFoo, the ObservableValues property doesn't exist.

A possible alternative would be to set FooControl.DataContext equal to Foo, and then make your binding simply ObservableValues so it is simply calling DataContext.ObservableValues instead of FooControl.Foo.ObservableValues

If that doesn't work, try putting the ObservableValues property on IFoo, or make the Values property a type which can be inherited by either IList or ObservableCollection such as Object

Upvotes: 1

GameAlchemist
GameAlchemist

Reputation: 19294

mmm... i don't get why you don't have ObservableFoo Implementing INotifyCollectionChanged, INotifyPropertyChanged.

Upvotes: 0

Related Questions