Это приложение MVVM.Есть окно и связанный класс модели представления.
В форме есть TextBox
, Button
и ListBox
.Кнопка привязана к DelegateCommand
с функцией CanExecute
.Идея состоит в том, что пользователь вводит некоторые данные в текстовое поле, нажимает кнопку, и данные добавляются в список.
Я хотел бы включить команду (и кнопку), когда пользователь вводит правильные данные в TextBox
.Теперь все работает так:
CanExecute()
метод содержит код, который проверяет правильность данных в свойстве, привязанном к текстовому полю. - Текстовое поле привязано к свойству в модели представления
UpdateSourceTrigger
установлен на PropertyChanged
, и свойство в представлении модели обновляется после каждого нажатия пользователем клавиши.
Проблема в том, что CanExecute()
не срабатывает, когда пользователь вводит данные в текстовое поле.Он не срабатывает даже тогда, когда текстовое поле теряет фокус.
Как я могу сделать эту работу?
Редактировать:
Re Комментарий Янко:
ДелегатКоманда реализована в шаблоне инструментария MVVM, и при создании нового проекта MVVM в решении есть команда Delegate.Насколько я видел в видео Prism, это должен быть тот же класс (или, по крайней мере, очень похожий).
Вот фрагмент кода XAML:
...
<UserControl.Resources>
<views:CommandReference x:Key="AddObjectCommandReference"
Command="{Binding AddObjectCommand}" />
</UserControl.Resources>
...
<TextBox Text="{Binding ObjectName, UpdateSourceTrigger=PropertyChanged}"> </TextBox>
<Button Command="{StaticResource AddObjectCommandReference}">Add</Button>
...
Просмотр модели:
// Property bound to textbox
public string ObjectName
{
get { return objectName; }
set {
objectName = value;
OnPropertyChanged("ObjectName");
}
}
// Command bound to button
public ICommand AddObjectCommand
{
get
{
if (addObjectCommand == null)
{
addObjectCommand = new DelegateCommand(AddObject, CanAddObject);
}
return addObjectCommand;
}
}
private void AddObject()
{
if (ObjectName == null || ObjectName.Length == 0)
return;
objectNames.AddSourceFile(ObjectName);
OnPropertyChanged("ObjectNames"); // refresh listbox
}
private bool CanAddObject()
{
return ObjectName != null && ObjectName.Length > 0;
}
Как я писал в первой части вопроса, работают следующие вещи:
- Установщик свойства для
ObjectName
запускается при каждом нажатии клавиши в текстовом поле - , если я ставлю
return true;
в CanAddObject()
, команда активна (кнопка для)
Мне кажется, что привязка верна.
То, что я не знаю, это как сделать CanExecute()
сработал в установщике ObjectName
свойства из приведенного выше кода.
Ре Бен и Абе ответили:
CanExecuteChanged()
- обработчик событий, и компилятор жалуется:
Событие 'System.Windows.Input.ICommand.CanExecuteChanged' может появляться только слева от + = или - =
тамтолько два члена ICommand
: Execute()
и CanExecute()
У вас есть пример, показывающий, как я могу сделать командный вызов CanExecute()
.
Я нашел класс помощника диспетчера команд в DelegateCommand.cs
, и я посмотрю на него, может быть, есть какой-то механизм, который мог бы помочь.
В любом случае, идея для того, чтобы активировать команду на основе пользователяввод, нужно "подтолкнуть" объект команды в коде установщика свойства выглядит неуклюже.Он будет вводить зависимости, и одна из важных особенностей MVVM - их уменьшение.
Редактировать 2:
Я попытался активировать CanExecute
, вызвав addObjectCommand.RaiseCanExecuteChanged()
на ObjectName
свойство setter из кода выше.Это тоже не помогает.CanExecute()
запускается несколько раз, когда форма инициализируется, но после этого она никогда не выполняется снова.Это код:
// Property bound to textbox
public string ObjectName
{
get { return objectName; }
set {
objectName = value;
addObjectCommand.RaiseCanExecuteChanged();
OnPropertyChanged("ObjectName");
}
}
Редактировать 3: Решение
Как Янко Янков и JerKimball написал, проблемаэто статический ресурс.Когда я изменил привязку кнопки, как предложил Янко:
<Button Command="{Binding AddObjectCommand}">Add</Button>
все сразу заработало.Мне даже не нужно RaiseCanExecuteChanged()
.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 11 * 11 * * 11 11 * .Пример в этом руководстве определяет команды как статический ресурс, а затем привязывает его к пункту меню.Разница в том, что вместо строкового свойства в моем примере руководство MVVM работает с ObservableCollection
.
Редактировать 4: Окончательное объяснение
Я наконец получил его.Все, что мне нужно было сделать, это прочитать комментарий в классе CommandReference
.Он говорит:
/// <summary>
/// This class facilitates associating a key binding in XAML markup to a command
/// defined in a View Model by exposing a Command dependency property.
/// The class derives from Freezable to work around a limitation in WPF when
/// databinding from XAML.
/// </summary>
Итак, CommandReference
используется для KeyBinding
, это не для связывания в визуальных элементах.В приведенном выше коде ссылки на команды, определенные в ресурсах, будут работать для связывания ключей, которого у меня нет в этом пользовательском элементе управления.
Конечно, пример кода, поставляемый с WPF MVVM toolkit, был верным, но я неправильно его прочитал и использовал CommandReference
в связывании визуальных элементов.
Этот WPF MVVM иногда бывает сложным.