Edward Tanguay
Edward Tanguay

Reputation: 193302

How do I pass the information from View to ViewModel with DelegateCommand?

In my View, I have a button.

When the user clicks this button, I want to have the ViewModel save the context of the TextBlock in the database.

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

However, in my DelegateCommand in my ViewModel, the "Save()" method doesn't pass any arguments, so how do I get data from the view at that point?

#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's textbox from here?....
}

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

Upvotes: 13

Views: 48833

Answers (6)

textblock inside grid, binding in view:

                            <telerik:GridViewDataColumn Header="Anunciante">
                            <telerik:GridViewDataColumn.CellTemplate>
                                <DataTemplate>
                                    <Grid Background="{Binding AnuncianteColor}" Margin="0,7,0,7" VerticalAlignment="Center"  >
                                        <TextBlock Text="{Binding Anunciante}" 
                                                   Padding="5,10,5,10" 
                                                   HorizontalAlignment="Stretch" 
                                                   TextAlignment="Center"
                                                   Tag="{Binding Index}"
                                                   MouseDown="AnuncianteMouseDown" />
                                    </Grid>
                                </DataTemplate>
                            </telerik:GridViewDataColumn.CellTemplate>
                        </telerik:GridViewDataColumn>

and a hidden button biding for command

<Button Visibility="Collapsed" x:Name="AnunciantedoubleClick" Command="{Binding AnuncianteClickCommand}"></Button>

code behind

        private void AnuncianteMouseDown(object sender, MouseButtonEventArgs e) 
    {
        //if (e.ClickCount == 2)
        //{
            this.AnunciantedoubleClick.Command.Execute(((TextBlock)sender).Tag);
        //}
    }

and finally code in ModelView:

public ICommand AnuncianteClickCommand { get; }

in a constructor:

this.AnuncianteClickCommand = new DelegateCommand<object>(this.AnuncianteClickDelegate);

and the delegate shows a message with the row index (custom messagebox service, sorry)

        private void AnuncianteClickDelegate(object v) 
    {
        MessageBoxService.Show(v.ToString());
    }

Upvotes: 0

Matt Hamilton
Matt Hamilton

Reputation: 204139

Check out this MSDN article by Josh Smith. In it, he shows a variation of DelegateCommand that he calls RelayCommand, and the Execute and CanExecute delegates on RelayCommand accept a single parameter of type object.

Using RelayCommand you can pass information to the delegates via a CommandParameter:

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

Update

Looking at this article, it appears that there is a generic version of DelegateCommand which accepts a parameter in a similar way. You might want to try changing your SaveCommand to a DelegateCommand<MyObject> and change your Save and CanSave methods so that they take a MyObject parameter.

Upvotes: 20

ml_black
ml_black

Reputation: 371

I'm not allowed to make comments yet, I guess. I'm responding to Carlos' suggestion because I tried it out. While it's a great idea, DelegateCommand would need to be modified in some way because otherwise you'll get this error: A field initializer cannot reference the non-static field, method, or property 'MyViewModel.Save(string)'.

Upvotes: 1

Ntx
Ntx

Reputation:

here is the elegant way.

Give a name to your textbox, then bind the CommandParameter in the button to it's Text property:

<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>

Upvotes: 13

Jeffrey Knight
Jeffrey Knight

Reputation: 5977

You're asking about passing data via the button Command.

What you actually want, I think, is to bind your Textbox's text to a public property in your ViewModel:

<!-- View: TextBox's 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's text is bound to --> this.FirstName;
}

Upvotes: 5

Carlos
Carlos

Reputation: 945

In your VM:

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

public ICommand SaveCmd{ get{ return _saveCmd } }

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

In you View, use CommandParameter like Matt's example.

Upvotes: 12

Related Questions