1
votes

(Now I'm Studying MVVM) I'm trying update current data(in a view model) with input data from UI. But the problem is ViewModel doesn't know about the View. So that I can't access to input data in a UI (like TextBox.Text).

(below) In MainPage.xaml contains two TextBoxes to get input data and a Button to Save input data

<StackPanel>
        <TextBox x:Name="NameTextBox" Margin="10" Header="Name text box" />
        <TextBox x:Name="AgeTextBox" Margin="10" Header="Age text box"/>

        <StackPanel Orientation="Horizontal">

            <Button x:Name="SaveButton" Content="&#xE105;" FontFamily="Segoe MDL2 Assets"  Margin="30,10"
                     CommandParameter="{x:Bind ViewModel.CreatedPerson, Mode=OneWay}"
                     Command="{x:Bind ViewModel.SaveCommand}"
                     Click="SaveButton_Click"/>
        </StackPanel>

        <StackPanel Orientation="Horizontal" Margin="20">
            <TextBlock Text="{x:Bind ViewModel.Person.Name, Mode=OneWay}" />
            <TextBlock Text="{x:Bind ViewModel.Person.Age, Mode=OneWay}" />
        </StackPanel>
    </StackPanel>

NameTextBox and AgeTextBox holds input data until SaveButton is clicked.

(Person is plain data model with name and age properties)

be aware : SaveButton above has Command and Click event both

(below) In MainPageViewModel.cs contains two properties and Command logic

public class MainPageViewModel : ViewModelBase
{
    public Person Person
    {
        get => _person;
        set { Set(nameof(Person), ref _person, value); }
    }
    private Person _person;

    public Person CreatedPerson
    {
        get => _createdPerson;
        set { Set(nameof(CreatedPerson), ref _createdPerson, value); }
    }
    private Person _createdPerson;

    public MainPageViewModel()
    {
        Person = new Person();
    }

    private RelayCommand<Person> _saveCommand;
    public RelayCommand<Person> SaveCommand
    {
        get
        {
            return _saveCommand
                ?? (_saveCommand = new RelayCommand<Person>(
                p =>
                {
                    Person.Name = p.Name;
                    Person.Age = p.Age;
                }));
        }
    }
}

MainPageViewModel contains Person and CreatedPerson properties. Person property contains current data. CreatedPerson property contains temporary data from UI. If SaveButton is clicked Person property is updated.

(below) In MainPage.xaml.cs (code-behind file) has ViewModel and SaveButton_Click event

public sealed partial class MainPage : Page
{
    private readonly MainPageViewModel ViewModel = new MainPageViewModel();

    public MainPage()
    {
        this.InitializeComponent();
    }

    private void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        var newPerson = new Model.Person
        {
            Name = NameTextBox.Text,
            Age = Convert.ToInt32(AgeTextBox.Text)
        };
        ViewModel.CreatedPerson = newPerson;
    }
}

SaveButton_Click event gets data from TextBoxes and save them in a ViewModel.

My Question is how can I pass UI data(in a TextBox) as a parameter of SaveCommand? MainPageViewModel don't know about TextBoxes in the view.

To solve this problem, I create SaveButton_Click event in code-behind to access TextBoxes data. SaveButton_Click gets data from TextBoxes and Save them to The ViewModel(at CreatedPerson property).

After CreatedPerson is set, SaveCommand in the ViewModel executed to update Person property.

As a result, when the SaveButton is clicked, SaveButton_Clicked event fires before SaveCommand. So my project works fine anyway, But it smells a lot.

  1. How can I solve this problem in a right way? Use converter? Now I'm trying to Use converter to pass CommandParameter, but stuck. SaveCommand need Person object as a parameter, and Person object need two data(name and age). how can I pass two parameter to a converter? using Tuple? :(

  2. With curiousity, click event always fired before Command?

2

2 Answers

0
votes

Set the view model object from the constructor in the code behind class.

You shouldn't use both Command and Click-event.

0
votes

In your command you can use the parameter parameter (no phun intended)

public void Execute(object parameter)
{
    viewModel.Reply1 = new Models.Reports.Reply();
    viewModel.ShowList = false;
}

In your XAML you would provide that parameter as such:

    <Button Command="{Binding UpdateCommand}" CommandParameter="TheParameterYouWantoToUseInTheExecute"