public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePropertyName) { var viewModelObservableProperty = viewModel.GetType().GetProperty(observablePropertyName); if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType && viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false && viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false) { throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePropertyName}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} "); } viewModel.SynchronizeForLifetime(observablePropertyName, () => { var newValue = viewModelObservableProperty.GetValue(viewModel); if (newValue == latestValue) { return; } latestValue = newValue; controlProperty.SetValue(control, newValue); }, control.LifetimeManager); control.SubscribeForLifetime(controlProperty.Name, () => { var newValue = controlProperty.GetValue(control); if (newValue == latestValue) { return; } latestValue = newValue; viewModelObservableProperty.SetValue(viewModel, newValue); }, control.LifetimeManager); }
public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePath, Func <object, object> mapper, Func <object, object> reverseMapper) { this.mapper = mapper; this.reverseMapper = reverseMapper; var exp = ObjectPathExpression.Parse(observablePath); var trace = exp.EvaluateAndTraceInfo(viewModel); var observableObject = trace[trace.Count - 2].Value as ObservableObject; var viewModelObservableProperty = trace.Last()?.MemberInfo as PropertyInfo; if (observableObject == null) { throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePath}' is not observable"); } if (viewModelObservableProperty == null) { throw new InvalidOperationException($"Cannot resolve ViewModel property '{viewModel.GetType().FullName}.{observablePath}'"); } if (mapper != null && reverseMapper != null) { if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType && viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false && viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false) { throw new InvalidOperationException($"ViewModel type '{viewModel.GetType().FullName} property {observablePath}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} "); } } observableObject.SynchronizeForLifetime(trace.Last().MemberInfo.Name, () => { var newValue = viewModelObservableProperty.GetValue(observableObject); if (newValue == latestValue) { return; } latestValue = newValue; controlProperty.SetValue(control, mapper != null ? mapper(newValue) : newValue); }, control.LifetimeManager); control.SubscribeForLifetime(controlProperty.Name, () => { var newValue = controlProperty.GetValue(control); if (newValue == latestValue) { return; } latestValue = newValue; viewModelObservableProperty.SetValue(observableObject, reverseMapper != null ? reverseMapper(newValue) : newValue); }, control.LifetimeManager); }