Я реорганизовал свое приложение WPF, чтобы DataContexts больше не были экземплярами какого-то класса, который реализует INotifyPropertyChanged
, а скорее мои собственные интерфейсы. Объект, который реализует каждый пользовательский интерфейс, также должен реализовывать INotifyPropertyChanged
. Но я больше не могу применять это требование во время сборки. Я не уверен, что это хорошая идея.
Например, рассмотрим следующую простую иерархию классов
// Base view model class has stock implementation of INotifyPropertyChanged.
public BaseViewModel : INotifyPropertyChanged
{
// Assume INotifyPropertyChanged implementation with this utility to raise the event
void RaisePropertyChanged(string property) { // ...blah blah blah ... }
}
// Interface for nameable object
public interface INameable
{
string Name { get; set; }
}
// View model for nameable object
public class NameableViewModel : BaseViewModel, INameable
{
private string _name;
public string Name
{
get => _name;
set
{
if (value == _name) return;
_name = value
RaisePropertyChanged();
}
}
// Main view model exposes named object by interface, NOT by view-model
public class MainViewModel : BaseViewModel
{
public INameable NameableObject { get; set; }
}
Вот привязка вида к INameable
вместо NameableViewModel
<UserControl x:Class="MyView"
(... blah blah blah... namespace declarations...)
d:DataContext="{d:DesignInstance MainViewModel}">
<TextBox DataContext={Binding NameableObject.Name, Mode=TwoWay}"/>
</UserControl>
Это прекрасно работает в WPF, потому что он запрашивает любой контекст данных для INotifyPropertyChanged
. Он получает уведомления PropertyChanged, хотя все, что он получил, было INameable
. Но если я забуду правильно настроить свои классы, WPF просто молча никогда не получит уведомления об изменении свойств. Я мог бы в конечном итоге иметь ошибки, которые нужно заметить или отследить (ресурсы тестирования здесь ограничены).
Кроме того, в своем коде я иногда вручную наблюдаю за некоторыми объектами через INotifyPropertyChanged
, используя превосходный PropertyObserver
Джоша Смита.
public class PropertyObserver<TPropertySource>
: IWeakEventListener
where TPropertySource : INotifyPropertyChanged
{
... blah blah blah..
}
Для этого требуется , требующий INotifyPropertyChanged во время сборки, и это было здорово, когда я использовал экземпляры моего BaseViewModel. Но теперь, когда у меня есть только интерфейс, я должен сам запросить его и полагаться на ошибку во время выполнения, чтобы сообщить мне, что я облажался.
Что приводит меня к моим вопросам. Один общий и один очень конкретный:
- Является ли этот дизайн разумным? Это то, что обычно делают люди, работающие в WPF? Или вообще всегда лучше быть уверенным, что любой тип, который я использую в качестве контекста данных, уже объявлен для реализации INotifyPropertyChanged? (Я понимаю, что, возможно, я слишком много думаю, как программист C ++ с этим вопросом)
- Предположим, в моем коде я приведу объект, и он НЕ поддерживает интерфейс, который мне требуется, и я хочу вызвать исключение. Какое конкретное исключение .NET я должен выбросить? Что наиболее подходит?
NotSupportedException
? Что-то еще?