Как передать информацию из View в ViewModel с DelegateCommand?

В моем представлении у меня есть кнопка.

Когда пользователь нажимает эту кнопку, я хочу, чтобы ViewModel сохранял контекст TextBlock в базе данных.

<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
    <TextBlock Text="{Binding FirstName}"/>
    <TextBox Text="Save this text to the database."/>
    <Button Content="Save" Command="{Binding SaveCommand}"/>
</StackPanel>

Однако в моей функции DelegateCommand в моей модели ViewModel метод "Сохранить()" не передает никаких аргументов, так как я могу получить данные из представления в этой точке?

#region DelegateCommand: Save
private DelegateCommand saveCommand;

public ICommand SaveCommand
{
    get
    {
        if (saveCommand == null)
        {
            saveCommand = new DelegateCommand(Save, CanSave);
        }
        return saveCommand;
    }
}

private void Save()
{
    TextBox textBox = ......how do I get the value of the view textbox from here?....
}

private bool CanSave()
{
    return true;
}
#endregion

Ответ 1

Ознакомьтесь с этой статьей MSDN Джошем Смитом. В нем он показывает вариант DelegateCommand, который он называет RelayCommand, а делегаты Execute и CanExecute в RelayCommand принимают один параметр объекта типа.

Используя RelayCommand, вы можете передавать информацию делегатам через CommandParameter:

<Button Command="{Binding SaveCommand}" 
        CommandParameter="{Binding SelectedItem,Element=listBox1}" />

Обновление

Рассматривая эту статью, похоже, что существует общая версия DelegateCommand, которая принимает параметр аналогичным образом. Возможно, вы захотите изменить свой SaveCommand на DelegateCommand<MyObject> и изменить методы сохранения и CanSave, чтобы они принимали параметр MyObject.

Ответ 2

вот элегантный способ.

Дайте имя своему текстовому полю, затем привяжите CommandParameter в кнопке к нему. Свойство "Текст":

<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
    <TextBlock Text="{Binding FirstName}"/>
    <TextBox x:Name="ParameterText" Text="Save this text to the database."/>
    <Button Content="Save" Command="{Binding SaveCommand}"
            CommandParameter="{Binding Text, ElementName=ParameterText}"/>
</StackPanel>

Ответ 3

В вашей виртуальной машине:

private DelegateCommand<string> _saveCmd = new DelegateCommand<string>(Save);

public ICommand SaveCmd{ get{ return _saveCmd } }

public void Save(string s) {...}

В представлении View используйте CommandParameter, например, пример Matt.

Ответ 4

Вы спрашиваете о передаче данных с помощью кнопки Command.

То, что вы на самом деле хотите, я думаю, это привязать текст вашего текстового текста к общедоступному свойству в вашей модели ViewModel:

<!-- View: TextBox text is bound to the FirstName property in your ViewModel -->
<TextBox Text="{Binding Path=FirstName}" />
<Button Command="{Binding SaveCommand}"/>

<!-- ViewModel: Expose a property for the TextBox to bind to -->
public string FirstName{ get; set; }
...
private void Save()
{
    //textBox text is bound to --> this.FirstName;
}

Ответ 5

Я не могу оставлять комментарии еще, я думаю. Я отвечаю на предложение Карлоса, потому что я попробовал это. Хотя это отличная идея, DelegateCommand нужно будет каким-то образом изменить, потому что в противном случае вы получите эту ошибку: Инициализатор поля не может ссылаться на нестатическое поле, метод или свойство "MyViewModel.Save(string)".