Propiedades de POCO de enlace de datos
-
03-07-2019 - |
Pregunta
¿Existen marcos de enlace de datos (BCL o de otro tipo) que permitan el enlace entre dos propiedades CLR que implementen INotifyPropertyChanged
y INotifyCollectionChanged
? Parece ser que debería ser posible hacer algo como esto:
var binding = new Binding();
binding.Source = someSourceObject;
binding.SourcePath = "Customer.Name";
binding.Target = someTargetObject;
binding.TargetPath = "Client.Name";
BindingManager.Bind(binding);
Donde someSourceObject
y someTargetObject
son solo POCO que implementan INotifyPropertyChanged
. Sin embargo, no conozco ningún soporte de BCL para esto, y no estoy seguro si hay marcos existentes que lo permitan.
ACTUALIZACIÓN : dado que no hay una biblioteca existente disponible, me he encargado de escribir la mía. Está disponible aquí .
Gracias
Solución
Escribí Truss para llenar el vacío.
Otros consejos
No conozco ninguna biblioteca que haga esto, pero podría escribir la suya con bastante facilidad.
Aquí hay una base que descubrí en unos minutos que establece el enlace de datos bidireccional entre dos propiedades simples:
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);
}
};
}
}
Por supuesto, este código carece de algunas sutilezas. Las cosas para agregar incluyen
- Comprobando que
fuente
ytarget
están asignados - Comprobando que las propiedades identificadas por
sourcePropertyName
ytargetPropertyName
existen - Comprobando la compatibilidad de tipos entre las dos propiedades
Además, Reflection es relativamente lento (aunque lo compara antes de descartarlo, no es que lento), por lo que es posible que desee utilizar expresiones compiladas en su lugar.
Por último, dado que la especificación de propiedades por cadena es propensa a errores, puede usar expresiones Linq y métodos de extensión en su lugar. Entonces en lugar de escribir
Binder.Bind( source, "Name", target, "Name")
podrías escribir
source.Bind( Name => target.Name);
AutoMapper puede copiar valores entre dos instancias, pero debe escribir su propio código para hacerlo. suceder automáticamente.
Quizás LINdable LINQ o cont. linq puede ayudar aquí. Si está intentando agregar propiedades de modelo que en realidad son "propiedades derivadas" de sus datos actuales y actualizados, para facilitar la vinculación de su UI, estos dos marcos deberían ayudar.
Escribí un pequeño proyecto Bind con soporte completo para el enlace entre propiedades neas y acciones de enlace asíncrono. El sintax no puede ser más simple:
//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);
Si definió sus propiedades como DependencyProperty 's podrías hacerlo. Tanto WF como WPF tienen una implementación (el primer enlace es para WPF. Para WF es this one) por lo que debe decidir cuál usar, pero ambos deberían ser suficientes para sus necesidades.