Home > Software design >  Unable to bind my DatePicker to my ViewModel
Unable to bind my DatePicker to my ViewModel

Time:10-22

I'm trying to implement a datepicker and bind it to a model I've created. I've made a global tournament object in App.xaml.cs:

private Tournament _tournament;
public Tournament tournament { 
    get { return _tournament; } 
    set { _tournament = value; OnPropertyChanged("tournament"); }  
}

And I've made an OnStartup override to launch my windows:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    //setup score
    score = new Score();
    // Tournament setup
    tournament = new Tournament();
    tournament.GamesToWin = 1;
    tournament.Games = new List<Game>(1);
    tournament.Players = new List<Player>(2) { new Player(), new Player() };
    //tournament.TimeAndDate = new DateTime(2021, 11, 22);
    tournament.Winner = null;

    // Initializing the UserInput
    UserInput userInput = new UserInput();
    UserInputWindowViewModel userinputViewModel = new UserInputWindowViewModel();
    userInput.DataContext = userinputViewModel;
    // Opening the UserInput Window
    bool? res = userInput.ShowDialog();
    // If the UserInput Window is closed, open the next Window
    if (res == true)
    {
        // Opening the MainWindow
        MainWindow main = new MainWindow();
        main.Show();
    }
    else
    {
        Shutdown();
    }
}

Model.cs (Tournament.cs):

public class Tournament : INotifyPropertyChanged
{
    private Player _winner;
    private DateTime? _timeAndDate;
    private List<Player> _players;
    public List<Player> Players
    {
        get { return _players; }
        set { _players = value; OnPropertyChanged("Players"); }
    }
    private List<Game> _games;

    public List<Game> Games
    {
        get { return _games; }
        set { _games = value; OnPropertyChanged("Games"); }
    }
    private int _gamesToWin;

    public int GamesToWin
    {
        get { return _gamesToWin; }
        set { _gamesToWin = value; OnPropertyChanged("GamesToWin"); }
    }
    public Player Winner
    {
        get { return _winner; }
        set { _winner = value; OnPropertyChanged("Winner"); }
    }
    public DateTime? TimeAndDate
    {
        get { return _timeAndDate; }
        set { _timeAndDate = value; OnPropertyChanged("TimeAndDate"); }
    }
    #region PropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

ViewModel.cs (UserInputWindowViewModel.cs):

public class UserInputWindowViewModel
{
    // Calling the current app to access the tournament object globally
    public App currentApp = Application.Current as App;
    #region The players object
    private List<Player> _players;
    public List<Player> Players
    {
        get { return _players; }
        set { _players = value; }
    }
    #endregion
    #region The DateTime object
    private DateTime? _dateTime;
    public DateTime? TournamentDateTime
    {
        get { return _dateTime; }
        set { _dateTime = value; }
    }

    #endregion
    public UserInputWindowViewModel()
    {
        Tournament tournament = currentApp.tournament;
        Players = tournament.Players;
        TournamentDateTime = new DateTime(2021, 11, 22);
        tournament.TimeAndDate = TournamentDateTime;
        //TournamentDateTime = tournament.TimeAndDate;
    }
    #region ICommand Members
    private ICommand mUpdater;
    public ICommand UpdateCommand
    {
        get
        {
            if (mUpdater == null)
                mUpdater = new Updater();
            return mUpdater;
        }
        set
        {
            mUpdater = value;
        }
    }

    private class Updater : ICommand
    {
        public bool CanExecute(object parameter) => true;
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {

        }
    }
    #endregion
}

Inside my window (UserInput.xaml) I have the following Datepicker:

<DatePicker SelectedDate="{Binding TournamentDateTime, Mode=TwoWay}"/>

I've set the date inside my viewmodel to 22-11-2021 as test, but when I change the date, it's not changing. What am I doing wrong?

EDIT: I also tried the OnPropertyChanged in the ViewModel, which didn't work

CodePudding user response:

You forgot to implement INotifyPropertyChanged under UserInputWindowViewModel.cs.

public class UserInputWindowViewModel : INotifyPropertyChanged
{
}

Also make sure you are triggering PropertyChanged event in property setter, it's important for two-way binding

public DateTime? TournamentDateTime
{
    get { return _dateTime; }
    set 
    {
         _dateTime = value; 
         OnPropertyChanged(nameof(TournamentDateTime);
     }
}

I'd also would suggest not to access Application directly from a view model, better pass tournament object as a dependency to a view model as soon it would be better separation of concerns

CodePudding user response:

I managed to fix my problem: I made a small function to update my global model:

public void updateModel(DateTime? s)
{
    currentApp.tournament.TimeAndDate = s;
}

I've added this small bit of code to my getter/setter inside my viewmodel (notice I used DateTime.Now to set it to the current date):

private DateTime? _dateTime = DateTime.Now;
public DateTime? TournamentDateTime
{
    get { return _dateTime; }
    set { _dateTime = value; updateModel(value); }
}

This fixed all my problems with the datepicker. And I didn't have to use INotifyPropertychanged inside my viewmodel because my model already had it implemented.

  • Related