DelegateCommand<T> Ссылка на объект не указывает на экземпляр объекта

Я добавляю новую кнопку с функциональностью в большое существующее клиентское приложение WPF. Кнопка Command должна запускать метод модели представления через DelegateCommand<T>. Проблема в том, что все приложение вылетает при запуске, видимо из-за этого DelegateCommand<T>. Мой код выглядит следующим образом.

BaseFormViewModel (унаследован от PensionTakerViewModel)

public DelegateCommand<DocumentType> AddFileCommand { get; private set; }

public BaseFormViewModel(...)
{
    this.AddFileCommand = new DelegateCommand<DocumentType>(this.ExecuteAddFileCommand);
}

protected virtual void ExecuteAddFileCommand(DocumentType documentType)
{
  // Do something...
}

PensionTakerView

<ctrl:ErrorDecorator Grid.Row = "1" Grid.Column = "0">
    <ComboBox AutomationProperties.AutomationId = "cmbDocumentType" 
              ItemsSource = "{Binding ViewModel.DocumentTypes, ElementName=Root}" 
              DisplayMemberPath = "Name" 
              SelectedValuePath = "Value"
              SelectedValue = "{Binding DocumentType}"/>
</ctrl:ErrorDecorator>
                
<Button Grid.Row = "1" Grid.Column = "2" Content = "Tilføj fil" 
        Command = "{Binding ViewModel.AddFileCommand, ElementName=Root}"
        CommandParameter = "{Binding DocumentType}"/>

Теперь приложение падает при запуске, и интересная часть трассировки стека выглядит следующим образом (я анонимизировал имена клиентов и термины). Извините за маленький размер изображения. DelegateCommand&lt;T&gt; Ссылка на объект не указывает на экземпляр объекта

Я новичок как в WPF, так и в MVVM, поэтому для меня это что-то вроде кривой обучения. Но, насколько я понимаю, он жалуется на второй параметр DelegateCommand<T>, который является методом CanExecute. Но у DelegateCommand<T> также есть конструктор, который принимает только один параметр — метод Execute. Так почему же он жалуется на это?

Я также пытался передать метод CanExecute, который просто возвращает true. Но приложение все равно вылетает с той же ошибкой.

Такое же использование DelegateCommand<T> существует в нескольких местах приложения с одинаковым синтаксисом и подписью без проблем. Так что это действительно не должно быть проблемой.

Я также пробовал использовать ICommand и ExecuteAddFileCommand без параметров. Это работает для меня, но, очевидно, не является решением, так как мне нужно передать DocumentType.

Может кто-нибудь, пожалуйста, помогите мне продвинуться дальше к решению?

Трудно сказать, не глядя на код DelegateCommand<T>, правда.

Etienne de Martel 17.03.2022 16:17

Вы по-прежнему получаете исключение, если измените тип на DelegateCommand<object>?

mm8 17.03.2022 16:20

@mm8 Но тогда код, вероятно, не скомпилируется, потому что тип делегата не будет совпадать.

Etienne de Martel 17.03.2022 16:27

@mm8 На самом деле нет .. Я изменил тип на объект, и он работает. По крайней мере, приложение не вылетает. Но теперь параметр ExecuteAddFileCommand() равен нулю. Несмотря на то, что я выбрал значение в поле со списком, которое затем должно быть привязано к свойству DocumentType в модели представления.

RonRonDK 17.03.2022 16:36

Итак, что такое DocumentType, к которому вы пытаетесь привязаться? Действительно ли это свойство возвращает DocumentType?

mm8 17.03.2022 16:37

Дайте угадаю, DocumentType — это тип значения (вероятно, перечисление)? В этом случае, если ваша команда получает нулевой параметр, приведение выдаст это исключение.

Etienne de Martel 17.03.2022 16:44

@EtiennedeMartel да DocumentType - это перечисление.

RonRonDK 17.03.2022 16:46

Хорошо, тогда это очевидно: привязка CommandParameter оценивается как null, а DelegateCommand<T> пытается привести свой параметр к T. Приведение null к типу значения вызовет исключение.

Etienne de Martel 17.03.2022 16:48

@EtiennedeMartel Хорошо, так что вы имеете в виду, что мое свойство DocumentType, к которому привязывается CommandParameter, не получает выбранное значение из поля со списком и, таким образом, передает значение null в DelegateCommand?

RonRonDK 17.03.2022 16:53

@RonRonDK: Кажется вероятным. Вы читали мой ответ?

mm8 17.03.2022 16:55

Если вы просто создадите экземпляр модели представления, произойдет ли ошибка?

Andy 17.03.2022 21:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
11
40
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я подозреваю, что параметр команды — это нечто иное, чем объект DocumentType.

Если вы измените тип команды на DelegateCommand<object>, вы должны избежать получения исключения.

Затем вы можете поставить точку останова в методе ExecuteAddFileCommand, чтобы определить фактический тип параметра и установлен ли он вообще. Если нет, проверьте исходное свойство DocumentType, к которому вы привязываете CommandParameter:

CommandParameter = "{Binding DocumentType}"

Его тип должен соответствовать аргументу типа DelegateCommand<T>.

Если бы это было «что-то еще», вы бы получили InvalidCastException. Поведение предполагает, что параметр имеет значение null, а DocumentType не является ссылочным типом.

Etienne de Martel 17.03.2022 16:45
null явно «нечто иное», чем фактическое значение какого-то типа, не так ли?
mm8 17.03.2022 16:49

Под этим я подразумеваю, что значение null имеет некоторые интересные последствия, в отличие от передачи несвязанного типа. Это значение по умолчанию? Резервное значение? Привязка не работает? Во всяком случае, это сужает пространство возможностей.

Etienne de Martel 17.03.2022 16:50

@EtiennedeMartel: Какую часть ответа вы считаете неправильной?

mm8 17.03.2022 16:51

Ничего страшного, я просто добавил к этому, не нужно так защищаться.

Etienne de Martel 17.03.2022 16:54

В порядке. Понятно. Спасибо.

mm8 17.03.2022 16:55

Я не понимаю, почему тип должен быть object, чтобы избежать исключения. Это потому, что параметр команды не имеет типа DocumentType?

RonRonDK 17.03.2022 17:02
object работает для (почти) каждого типа. Вот почему я предложил вам попробовать с этим. После того, как вы разобрались, вы должны изменить фактический тип, который, по-видимому, в вашем случае Nullable<DocumentType>.
mm8 18.03.2022 14:22

Поэтому сегодня я углубился в это, следуя теории @mm8 о том, что мой CommandParameter не был типом DocumentType. Поэтому я проследил за DocumentType до конца и обнаружил, что в некоторых местах он обнуляемый, а в других нет. И как только я сменил CommandParameter на тип DocumentType?, приложение перестало падать. Мой входящий параметр в ExecuteAddFileCommand() все еще был null. И это было, конечно, потому, что я должен был включить параметр в DelegateCommand<T>. Итак, рабочий код выглядит так.

BaseFormViewModel (унаследован от PensionTakerViewModel)

public DelegateCommand<DocumentType?> AddFileCommand { get; private set; }

public BaseFormViewModel(...)
{
    this.AddFileCommand = new DelegateCommand<DocumentType?>(param => this.ExecuteAddFileCommand(param));
}

protected virtual void ExecuteAddFileCommand(DocumentType? documentType)
{
  // Do something...
}

Так почему вы не приняли или не проголосовали за мой ответ?

mm8 18.03.2022 14:22

@mm8 Ваш ответ помог мне продвинуться дальше, но не стал прямым решением проблемы. Так что я на самом деле не уверен, принимать ли это как ответ в соответствии с правилами SO?

RonRonDK 18.03.2022 14:28

Что заставляет вас говорить, что изменение аргумента типа не было «прямым решением проблемы»...?

mm8 18.03.2022 14:31

@ mm8 Ты прав .. Я принял твой ответ. Спасибо за вашу помощь.

RonRonDK 18.03.2022 14:33

Другие вопросы по теме