protected override void OnPropertyChanged(AdvancedPropertyChangedEventArgs e)
{
if (IsSaving || IsCanceling || IsClosing || IsClosed)
{
return;
}
if (string.IsNullOrEmpty(e.PropertyName))
{
return;
}
lock (_modelLock)
{
if (_modelObjects.ContainsKey(e.PropertyName))
{
// Clean up old model
var oldModelValue = _modelObjects[e.PropertyName];
if (oldModelValue != null)
{
UninitializeModelInternal(e.PropertyName, oldModelValue, ModelCleanUpMode.CancelEdit);
}
var newModelValue = GetValue(e.PropertyName);
_modelObjects[e.PropertyName] = newModelValue;
if (newModelValue != null)
{
InitializeModelInternal(e.PropertyName, newModelValue);
}
// Since the model has been changed, copy all values from the model to the view model
foreach (KeyValuePair<string, ViewModelToModelMapping> viewModelToModelMap in _viewModelToModelMap)
{
ViewModelToModelMapping mapping = viewModelToModelMap.Value;
IViewModelToModelConverter converter = mapping.Converter;
if (string.CompareOrdinal(mapping.ModelProperty, e.PropertyName) == 0)
{
var values = new object[mapping.ValueProperties.Length];
if (newModelValue != null)
{
// We have a new model, ignore OneWayToSource
if (mapping.Mode == ViewModelToModelMode.OneWayToSource)
{
continue;
}
for (var index = 0; index < mapping.ValueProperties.Length; index++)
{
var property = mapping.ValueProperties[index];
values[index] = PropertyHelper.GetPropertyValue(newModelValue, property, false);
}
}
else
{
var property = mapping.ViewModelProperty;
var propertyData = GetPropertyData(property);
values[0] = propertyData.GetDefaultValue();
}
values[0] = converter.Convert(values, this);
SetValue(mapping.ViewModelProperty, values[0], true, ValidateModelsOnInitialization);
}
}
}
}
// If we are validating, don't map view model values back to the model
if (!IsValidating)
{
if (_viewModelToModelMap.ContainsKey(e.PropertyName))
{
lock (_modelLock)
{
var mapping = _viewModelToModelMap[e.PropertyName];
var model = _modelObjects[mapping.ModelProperty];
if (model != null)
{
var modelInfo = _modelObjectsInfo[mapping.ModelProperty];
if (!modelInfo.IsCanceling)
{
var viewModelValue = GetValue(e.PropertyName);
var propertiesToSet = mapping.ValueProperties;
#if !WINDOWS_PHONE && !NET35 && !XAMARIN_FORMS
if (_modelErrorInfo.ContainsKey(mapping.ModelProperty))
{
mapping.ValueProperties.ForEach(_modelErrorInfo[mapping.ModelProperty].ClearDefaultErrors);
}
#endif
// Only TwoWay, OneWayToSource mappings should be mapped
if ((mapping.Mode == ViewModelToModelMode.TwoWay) || (mapping.Mode == ViewModelToModelMode.OneWayToSource))
{
var valuesToSet = mapping.Converter.ConvertBack(viewModelValue, this);
if (propertiesToSet.Length != valuesToSet.Length)
{
Log.Error("Properties - values count mismatch, properties '{0}', values '{1}'",
string.Join(", ", propertiesToSet), string.Join(", ", valuesToSet));
}
for (int index = 0; index < propertiesToSet.Length && index < valuesToSet.Length; index++)
{
if (PropertyHelper.TrySetPropertyValue(model, propertiesToSet[index], valuesToSet[index], false))
{
Log.Debug("Updated property '{0}' on model type '{1}' to '{2}'", propertiesToSet[index], model.GetType().Name, ObjectToStringHelper.ToString(valuesToSet[index]));
}
else
{
Log.Warning("Failed to set property '{0}' on model type '{1}'", propertiesToSet[index], model.GetType().Name);
}
}
}
}
}
else
{
Log.Warning("Value for model property '{0}' is null, cannot map properties from view model to model", mapping.ModelProperty);
}
}
}
}
if (InvalidateCommandsOnPropertyChanged)
{
ViewModelCommandManager.InvalidateCommands();
}
}