У меня есть объект, который создается путем десериализации некоторого XML.Я использовал инструмент Visual Studio для генерации XSD из XML-макета производителя.Затем, используя инструмент XSD, я получил от них классы.Я установил инструмент XSD таким образом, чтобы сгенерированные классы были INotifyPropertyChanged.
Теперь я пытаюсь отобразить этот объект на вкладке в моем приложении WPF.Мне нужен «грязный» индикатор всякий раз, когда кто-то вносит изменения.Проблема в том, что этот объект, будучи сгенерированным классом из сгенерированного XSD, не является самой красивой структурой.Отображение для этого объекта не имитирует его структуру данных.Я думал о создании экранных объектов (без использования банкомата MMVM) и об их использовании, чтобы связать мои изменения с последующим сохранением этих изменений в объекте в качестве объекта данных.По сути, я бы просто выбросил свой текущий дисплей, чтобы сделать это, так как сейчас я просто добавляю проверку на наличие изменений.
Я думаю, что нужно отразить объект и установить событие PropertyChanged для каждого свойства, которое япопадаются (прогуливаясь по графику объектов и свойств).Мое размышление фу меня подводит, и я также, вероятно, допускаю некоторые недальновидные ошибки.
Вот код, который я написал до сих пор:
void SetupPropertyChanged(INotifyPropertyChanged component)
{
component.PropertyChanged += CAMConfig_PropertyChanged;
Type componentType = component.GetType();
foreach (PropertyInfo info in componentType.GetProperties())
{
Type[] types =
info.PropertyType.FindInterfaces((a, b) => { return a.ToString() == b.ToString(); }, typeof(INotifyPropertyChanged));
bool isINotify = types.Contains(typeof(INotifyPropertyChanged));
if (isINotify)
this.SetupPropertyChanged((INotifyPropertyChanged)info.GetValue(component, new object[] { }));
}
}
Я думаю, что ясталкивается с проблемами типа свойства Observable коллекции, поскольку вызывает исключение, когда я пересекаю свой объект.Меня также поразило, что я не знаю, будет ли эта структура объекта иметь циклические ссылки.
Может ли кто-нибудь помочь мне разработать этот код, чтобы я мог пройти по графу объектов.Прямо сейчас я не слишком обеспокоен возможностью циклических ссылок, но если решение, которое предотвращает эту ситуацию, будет очень, очень полезно!
Основываясь на ответе Карела, я создал этого «помощника»."класс:
public static class NotifyPropertyChangedHelper
{
public delegate void ChangeOccuredHandler(object sender);
public static void SetupPropertyChanged(INotifyPropertyChanged component, ChangeOccuredHandler changedHandler)
{
SetupPropertyChanged(new List<object>(), component, changedHandler);
}
static void SetupPropertyChanged(IList<object> closed, INotifyPropertyChanged component, ChangeOccuredHandler changedHandler)
{
if (closed.Contains(component)) return; // event was already registered
closed.Add(component); //adds the property that is to be processed
//sets the property changed event if the property isn't a collection
if (!(component is INotifyCollectionChanged))
component.PropertyChanged += (sender, e) =>
{
changedHandler(sender);
};
/*
* If the component is an enumerable there are two steps. First check to see if it supports the INotifyCollectionChanged event.
* If it supports it add and handler on to this object to support notification. Next iterate through the collection of objects
* to add hook up their PropertyChangedEvent.
*
* If the component isn't a collection then iterate through its properties and attach the changed handler to the properties.
*/
if (component is IEnumerable<object>)
{
if (component is INotifyCollectionChanged)
{
//((INotifyCollectionChanged)component).CollectionChanged += collectionHandler;
((INotifyCollectionChanged)component).CollectionChanged += (sender, e) =>
{
changedHandler(sender);
};
}
foreach (object obj in component as IEnumerable<object>)
{
if (obj is INotifyPropertyChanged)
SetupPropertyChanged(closed, (INotifyPropertyChanged)obj, changedHandler);
}
}
else
{
foreach (PropertyInfo info in component.GetType().GetProperties())
{
var propertyValue = info.GetValue(component, new object[] { });
var inpc = propertyValue as INotifyPropertyChanged;
if (inpc == null) continue;
SetupPropertyChanged(closed, inpc, changedHandler);
}
}
}
}