0

I have a questionnaire application and I would like to display the objects (questions + answers in my case) one at a time. Meaning that I would like the user to be displayed the first question, answer it, then click a button and get the 2nd question (in the same window), click another button / or the same button and get the 3rd question and so on. At the moment, I am having difficulties trying to bind the 2nd question to my button by using only XAML. Is it possible to do this without using code behind? If so please do give me an idea. Thank you in anticipation.

This is my ViewModel:

namespace TestAppMVVM.ViewModel
{
    public class TestViewModel
    {
        public ObservableCollection<Test> BeginnerTests
        {
            get;
            set;
        }

        public Test CurrentQuestion
        {
            get;
            set;
        }

        public Test NextQuestion
        {
            get;
            set;
        }

        public Test CurrentAnswer
        {
            get;
            set;
        }

        public Test NextAnswer
        {
            get;
            set;
        }




        public void LoadBeginner()
        {
            ObservableCollection<Test> tests = new ObservableCollection<Test>();

            tests.Add(new Test { Index = 1, Question = "1.What is the capital of England ?", FirstAnswer = "Paris", SecondAnswer = "London", ThirdAnswer = "Berlin" });
            tests.Add(new Test { Index = 2, Question = "2.What is the capital of France ?", FirstAnswer = "Paris", SecondAnswer = "London", ThirdAnswer = "Berlin" });
            tests.Add(new Test { Index = 3, Question = "3.What is the capital of Germany ?", FirstAnswer = "Paris", SecondAnswer = "London", ThirdAnswer = "Berlin" });


            BeginnerTests = tests;
            CurrentQuestion = BeginnerTests[0];
            CurrentAnswer = BeginnerTests[0];

            NextQuestion = BeginnerTests[1];
            NextAnswer = BeginnerTests[1];

        }
    }
}   

And here I paste the View:

<Grid Background="Yellow">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="20"/>
        <ColumnDefinition Width="auto"/>
        <ColumnDefinition Width="auto"/>
        <ColumnDefinition Width="auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="20"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height ="20"/>
        <RowDefinition Height ="100"/>
        <RowDefinition Height ="auto"/>
        <RowDefinition Height ="auto"/>
        <RowDefinition Height ="30"/>
        <RowDefinition Height ="*"/>
        <RowDefinition Height ="20"/>
    </Grid.RowDefinitions>

    <TextBlock Grid.Column="1" Grid.Row="1" FontSize="25" Grid.ColumnSpan="3" Text="{Binding CurrentQuestion.Question}"/>

    <StackPanel Orientation="Horizontal" Grid.Column="2" Grid.Row="3" Grid.ColumnSpan="5">
        <RadioButton FontWeight="Bold" Content="{Binding CurrentAnswer.FirstAnswer}"/>
        <RadioButton FontWeight="Bold" Margin="10 0 0 0" Content="{Binding CurrentAnswer.SecondAnswer}"/>
        <RadioButton FontWeight="Bold" Margin="10 0 0 0" Content="{Binding CurrentAnswer.ThirdAnswer}"/>
    </StackPanel>


    <Button FontWeight="Bold" x:Name="nextButton" Content="Next Question" Grid.Column="2" Grid.Row="5"/>
Dev
  • 1,780
  • 3
  • 18
  • 46
StefanC
  • 11
  • 1
  • 4

2 Answers2

0

There's a way which is exposing an ICommand in ViewModel named MoveNext

The ICommand interface is here https://msdn.microsoft.com/en-us/library/system.windows.input.icommand(v=vs.110).aspx

class MoveNextCommand : ICommand 
{
    ...... <Your implementation>
}

public class TestViewModel 
{
    ...
    private ICommand _moveNextCmd;
    public ICommand MoveNextCmd 
    {
        get { return _moveNextCmd ?? (_moveNextCmd = new MoveNextCommand()); }
    }
    ...
}

In XAML

<Button FontWeight="Bold" x:Name="nextButton" Content="Next Question" Grid.Column="2" Grid.Row="5" Command={Binding MoveNextCmd} />

The command's logic is just changing the CurrentQuestion of the ViewModel.

The important thing here is that your ViewModel must implement INotifyPropertyChanged interface and setter of the properties must call OnPropertyChanged, otherwise you won't see any update when changing the property's value.

Khoa Nguyen
  • 1,056
  • 2
  • 12
  • 20
0

If you want to avoid using the code behind and implement MVVM for this, you will need to implement ICommand.

Put this in your ViewModel:

public ICommand ExecuteCommand
    {
        get
        {
            if (_command == null)
            {
                _command = new RelayCommand(param => this.NextQuestion());
            }
            return _command;
        }
    }

    public void NextQuestion()
    {
        //Do Stuff Here

    }

Bind your button to it by adding this to your XAML:

Command="{Binding Path=ExecuteCommand}"

And, finally, add a RelayCommand class to your project:

public class RelayCommand : ICommand
{

    readonly Action<object> _ActionToExecute;
    readonly Predicate<object> _ActionCanExecute;

    public RelayCommand(Action<object> inActionToExecute): this(inActionToExecute, null)
    {

    }

    public RelayCommand(Action<object> inActionToExecute, Predicate<object> inActionCanExecute)
    {
        if (inActionToExecute == null)
            throw new ArgumentNullException("execute");

        _ActionToExecute = inActionToExecute;
        _ActionCanExecute = inActionCanExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _ActionCanExecute == null ? true : _ActionCanExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _ActionToExecute(parameter);
    }
}
Pierce
  • 143
  • 10
  • Hello Pierce. Thank you for your reply, I have one question though what should "_command" be ? It says that it is out of context. – StefanC Mar 15 '18 at 10:47