Подтвердить что ты не робот

Свойства привязки данных POCO

Существуют ли какие-либо рамки привязки данных (BCL или иначе), которые позволяют связывать между любыми двумя свойствами CLR, которые реализуют INotifyPropertyChanged и INotifyCollectionChanged? Кажется, должно быть возможно сделать что-то вроде этого:

var binding = new Binding();
binding.Source = someSourceObject;
binding.SourcePath = "Customer.Name";
binding.Target = someTargetObject;
binding.TargetPath = "Client.Name";
BindingManager.Bind(binding);

Где someSourceObject и someTargetObject - это только POCOs, которые реализуют INotifyPropertyChanged. Тем не менее, я не знаю о какой-либо поддержке BCL для этого, и я не уверен, существуют ли существующие рамки, которые разрешают это.

ОБНОВЛЕНИЕ. Учитывая, что нет существующей библиотеки, я взял на себя обязательство написать свой собственный. Он доступен здесь.

Спасибо

4b9b3361

Ответ 1

Я написал Truss, чтобы заполнить пустоту.

Ответ 2

Я не знаю ни одной библиотеки, которая это делает, но вы могли бы написать свой собственный довольно легко.

Здесь база, которую я забил за несколько минут, которая устанавливает двухстороннюю привязку данных между двумя простыми свойствами:

public static class Binder
{

    public static void Bind(
        INotifyPropertyChanged source,
        string sourcePropertyName,
        INotifyPropertyChanged target,
        string targetPropertyName)
    {
        var sourceProperty
            = source.GetType().GetProperty(sourcePropertyName);
        var targetProperty
            = target.GetType().GetProperty(targetPropertyName);

        source.PropertyChanged +=
            (s, a) =>
            {
                var sourceValue = sourceProperty.GetValue(source, null);
                var targetValue = targetProperty.GetValue(target, null);
                if (!Object.Equals(sourceValue, targetValue))
                {
                    targetProperty.SetValue(target, sourceValue, null);
                }
            };

        target.PropertyChanged +=
            (s, a) =>
            {
                var sourceValue = sourceProperty.GetValue(source, null);
                var targetValue = targetProperty.GetValue(target, null);
                if (!Object.Equals(sourceValue, targetValue))
                {
                    sourceProperty.SetValue(source, targetValue, null);
                }
            };
    }
}

Конечно, в этом коде не хватает нескольких тонкостей. Что добавить:

  • Проверка того, что source и target назначены
  • Проверка того, что свойства, идентифицированные sourcePropertyName и targetPropertyName, существуют
  • Проверка совместимости типов между двумя свойствами

Кроме того, Reflection относительно медленный (несмотря на то, что он сравнивает его перед отбрасыванием, это не так медленно), поэтому вместо этого вы можете использовать скомпилированные выражения.

Наконец, учитывая, что указание свойств по строкам является склонным к ошибкам, вместо этого вы можете использовать выражения Linq и методы расширения. Затем вместо записи

Binder.Bind( source, "Name", target, "Name")

вы могли написать

source.Bind( Name => target.Name);

Ответ 3

AutoMapper может копировать значения между двумя экземплярами, но вы должны написать свой собственный код, чтобы это произошло автоматически.

Ответ 4

Может быть Bindable LINQ или непрерывный linq может помогите здесь. Если вы пытаетесь добавить свойства модели, которые на самом деле являются "производными свойствами" вашего фактического, обновляя данные, чтобы упростить для вас интерфейс, эти две структуры должны помочь.

Ответ 5

Я написал небольшой проект Bind с полной поддержкой связывания между асинхронными действиями привязки нестандартных свойств. Синтаксис не может быть проще:

//Two way binding between neasted properties:
Bind.TwoWay(()=> client.Area.Data.Name == this.AreaName);

//On change action execute:
Bind
    .OnChange(()=> client.Personal.Name)
    .Do(x => clientName = x);

Ответ 6

Если вы определили свои свойства как DependencyProperty, вы можете это сделать. У WF и WPF есть реализация (первая ссылка для WPF. Для WF это this one), поэтому вам нужно решить, но оба должны быть достаточными для ваших нужд.