Обновление DisplayName в коде, не отображается в дизайнере?
Это должно быть легко, но я не могу понять это. Когда изменяется какое-либо свойство моей пользовательской активности (например, путем изменения его в сетке свойств в конструкторе WF), я хочу динамически обновлять DisplayName. Я делаю это в коде установщика свойств:
public sealed class TarpSpecItem : Activity, ITarpSpecItem, INotifyPropertyChanged
{
...
public DocumentationType Type
{
get { return _type; }
set { _type = value;
DisplayName = "<" + value.ToString() + ">";
OnPropertyChanged("DisplayName");
OnPropertyChanged("Type");
}
}
Операция реализует INotifyPropertyChanged. Тем не менее, DisplayName не изменяется на поверхности дизайнера. Что мне не хватает?
Уилл ответ правильный. Я вставляю обновленный код дизайнера *.xaml.cs здесь в качестве отдельного ответа, чтобы иметь правильное форматирование (невозможно в качестве комментария). Этот код копирует и делает свое дело.
protected override void OnModelItemChanged(object newItem)
{
ModelItem modelItem = newItem as ModelItem;
if (modelItem != null)
modelItem.PropertyChanged += this.ModelItemPropertyChangedHandler;
base.OnModelItemChanged(newItem);
}
private void ModelItemPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
if (!e.PropertyName.Equals("Type", StringComparison.OrdinalIgnoreCase))
return;
ModelItem.Properties["DisplayName"].SetValue("<" + ModelItem.Properties["Type"].Value +">");
}
Эта упаковка активности внутри модельного элемента не делает решение очевидным, не так ли? Трудно понять, что происходит, но это действительно работает. Отличная работа, Уилл!
1 ответ
Ваш Activity
завернут в ModelItem
, который обрабатываетвсе сервисы уведомлений между Activity и поверхностью дизайна.
Когда он изначально находится внутри дизайнера, ModelItem
не проверяет ваш Activity
чтобы увидеть, если он предоставляет какой-либо метод уведомления об изменении свойства (INPC, пользовательскийTypeDescriptor
и т. д.) или другие интерфейсы (т.е. IDataErrorInfo
, для которого у меня есть связь здесь).
Таким образом, по сути, вы не можете делать то, что вы пытаетесь достичь здесь. Изнутри действия вы не можете отправить уведомление об изменении обратно через обертку ModelItem. Что ты действительно не должен делать, во всяком случае.
В конструкторе изменение состояния должно проходитьтолько через ModelItem
, так как он должен держать свое состояние в синхронизации с завернутымActivity
, Если его состояние и состояние обернутого экземпляра сместятся, вы не увидите правильную информацию в конструкторе.
// we're doing this in the designer
var activity = ModelItem.GetCurrentValue() as MyActivity;
activity.DisplayName = "You won't ever see this in the design surface!";
Вместо этого вы должны внести изменения в кодчерезModelItem
// again, in the designer code
ModelItem.Properties["DisplayName"].Value = "You will see this change!";
Итак, каково решение? Единственное реальное решение -убедиться, что вашActivities
пассивны, когда их состояние меняется! Изменения значения свойства не должны вызывать ничего.
Вместо этого перенесите такой код в конструктор!
override OnModelItemChanged(object obj)
{
// live dangerously!
var mi = obj as ModelItem;
mi.PropertyChanged += OnPropertyChanged;
}
void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(!e.PropertyName.Equals("Type", StringComparison.OrdinalIgnoreCase))
return;
ModelItem.Properties["DisplayName"].Value =
"<" +
ModelItem.Properties["Type"].GetCurrentValue().ToString() +
">";
}
Конечно, вы не можете просто скопировать это. И это может иметь некоторые ошибки. Но это дает вам представление о том, что вы должны делать.