Привязка к свойству, не указанному в интерфейсе - PullRequest
0 голосов
/ 17 ноября 2011

Название немного размыто, я не нашел способа сказать это более четко.

Давайте рассмотрим простой и очень понятный пример моей ситуации:

Первый: у меня есть пользовательский элемент управления FooControl с DependencyProperty типа IFoo. Элемент управления должен отображать IFoo объектов в DataGrid

Обратите внимание, что, конечно, реальный объект не просто отображает некоторые значения, я мог бы использовать только DataGrid для этого вопроса;)

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

Второе: у меня IFoo интерфейс

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

Третье: у меня есть Foo объект, реализующий IFoo

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

А теперь я хочу ObservableFoo, для привязки обновлений, вот оно:

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

Теперь ПРОБЛЕМА:

У меня обычно FooControl привязаны к объектам типа Foo, которые являются "строгими" реализациями интерфейса IFoo. Теперь мне также нужно иметь три FooControl s, которые должны быть привязаны к объектам типа ObservableFoo (которые, очевидно, IFoo, но также добавить свойство, не указанное в интерфейсе, то есть ObservableValues)

в классе FooControl я вручную установил привязку к отображаемым значениям:

    /// <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);
    }

Когда propertyPath равен Foo.Values, он работает нормально, обновление цели привязки вызовет PropertyChangedHandler, который я определил для ItemsSource

Когда propertyPath равно Foo.ObservableValues, обновление привязки не вызовет PropertyChangedHandler, который я определил. Однако в окне вывода не отображается ошибка привязки!

В моем понимании проблемы это означает, что:

  • Переплет "сработал", т.е. найдено исходное свойство
  • НО, поскольку ObservableValues не в IFoo, а только в ObservableFoo, привязка пытается найти IFoo.ObservableValues и ... не может его обновить.

Как мне удалось обновить привязку до ObservableValues?

Надеюсь, я достаточно ясно дал вам понять, ребята. Пожалуйста, не стесняйтесь задавать любые вопросы, если вам нужно, чтобы я уточнить

Ответы [ 3 ]

1 голос
/ 18 ноября 2011

Я думаю, что проблема связана с вашей привязкой.

Вы привязываетесь к RelativeSource Self, что означает, что ваша привязка читает FooControl.Foo.ObservableValues, а поскольку Foo определяется как IFoo, свойство ObservableValues не существует.

Возможной альтернативой было бы установить FooControl.DataContext равным Foo, а затем сделать привязку просто ObservableValues, чтобы она просто вызывала DataContext.ObservableValues вместо FooControl.Foo.ObservableValues

Если это не сработает, попробуйте установить свойство ObservableValues на IFoo или сделать свойство Values типом, который может быть унаследован либо IList, либо ObservableCollection, например Object

0 голосов
/ 22 ноября 2011

Хорошо, я наконец-то пошел на обход.

Я добавил свойство к 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;
            }
        }
    }

И я связываю встраиваемый Datagrid ItemSource с этим свойством (используя RelativeSource, указывающий на себя) и ... Он отлично работает.

Но, тем не менее, это заставило меня кое-что узнать: привязка не разрешает типы во время выполнения, она, очевидно, просто примет указанный тип!

0 голосов
/ 17 ноября 2011

ммм ... я не понимаю, почему у вас в ObservableFoo нет реализации INotifyCollectionChanged, INotifyPropertyChanged.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...