3

Right now I have a calender that only displays one month(what ever month I pass in). I'm trying to let the user pick what month and year from a comboBox and have the calender update. I'm binding using observablecollection which I'm sort of familiar with. I have no clue how INotifyPropertyChanged works though. I've never used it before. Any help or advice is greatly appreciated. This is what I have so far:

public class Schedule : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void Update(int propertyName)
    {
        if (propertyName != null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                 handler.Invoke(this, new PropertyChangedEventArgs(propertyName.ToString()));
        }
    }


   // public void UpdateCal(PropertyChangedEventArgs e)
   // {
    //    if (PropertyChanged != null)
    //        PropertyChanged(this, e);
  //  } 
    public string MonthWeek { get; set; }
    public string Year { get; set; }
    public string Month { get; set; }
    public string day { get; set; }
    public string WeekOfYear { get; set; }
    public string dayofweek { get; set; }

   // public string month {
    //    get {return Month; }
    //    set
    //    {
     //       UpdateCal(new PropertyChangedEventArgs("month"));
      //  }
   // }
    public int WeekNo { get; set; }
    public int WeekDay { get; set; }
    public DateTime Date { get; set; }
 }

---This is another class that figures out where to place each date on the grid----

           public SchedulePage(MainWindow parentForm)
    {
        InitializeComponent();

        pick = Convert.ToInt32(comboMonth.SelectedItem) + 1;
        _parentForm = parentForm;
        // DateTime date = new DateTime(year, month, day);
        var t = new List<Schedule>();
        DateTime curr = DateTime.Now;
      //  comboMonth.Items.Add(curr.Month);
        DateTime newcurr = new DateTime(2011, pick, 1);
     //   pickdate = datePickercal.SelectedDate;
      //  DateTime newcurr = new DateTime(curr.Year, curr.Month, 1);
        var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
        var ms = cal.GetWeekOfYear(new DateTime(newcurr.Year, newcurr.Month, 1), System.Globalization.CalendarWeekRule.FirstDay, System.DayOfWeek.Sunday);
        for (var i = 1; newcurr.Month == pick; newcurr = newcurr.AddDays(1))
        {
            var sched = new Schedule();
            var month_week = (newcurr.Day / 7) ;
            sched.MonthWeek = newcurr.GetWeekOfMonth().ToString();
            sched.Month = newcurr.Month.ToString();
            sched.Year = newcurr.Year.ToString();
            sched.day = newcurr.Day.ToString();
            sched.WeekOfYear = cal.GetWeekOfYear(newcurr, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString();
            sched.dayofweek = newcurr.DayOfWeek.ToString();
            t.Add(sched);

                _parentForm.bindings.schedule.Add(new Schedule { WeekNo = newcurr.GetWeekOfMonth()-1, WeekDay = (int)newcurr.DayOfWeek, day = newcurr.Day.ToString() });

        }
        lblDate.Content = (newcurr.Month -1) + "/" + newcurr.Year;

         DataContext = _parentForm.Bindings;

---And this class makes the observablecollections-----

           public partial class BindingCamper 
{  // This class assist in binding campers from listview to the textboxes on the camperspage
    public ObservableCollection<Camper> Campers { get; set; }
    public ObservableCollection<Staff> StaffMembers { get; set; }
    public ObservableCollection<Schedule> schedule { get; set; }
    public BindingCamper()
    {
        Campers = new ObservableCollection<Camper>();
      StaffMembers = new ObservableCollection<Staff>();
      schedule = new ObservableCollection<Schedule>();
    }
TMan
  • 4,044
  • 18
  • 63
  • 117

3 Answers3

7

This is how you typically implement INotifyPropertyChanged:

public class Schedule : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    private string _monthWeek;
    public string MonthWeek
    {
        get { return _monthWeek; }
        set
        {
            if (value != _monthWeek)
            {
                _monthWeek = value;
                OnPropertyChanged("MonthWeek");
            }
        }
    }

    // And so on for other properties...

}

Basically, you just need to trigger the PropertyChanged event every time a property is updated, so every setter must call OnPropertyChanged. Note that you can't do it with auto-implemented properties, since you need to add custom logic in the setter.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • You can do it with auto-implemented properties, but it's recommended not to. It's better to self-contain the OnPropertyChanged rather than relying on the code changing them to fire it. Though, this really only applies to OneWay properties since the UI should not be able to fire off OnPropertyChanged. – myermian Oct 28 '11 at 20:15
  • @m-y - How can you implement INotifyPropertyChanged with auto-implemented properties? – CodeNaked Oct 28 '11 at 20:21
  • @m-y, sure, you can call OnPropertyChanged from anywhere in the class, but in that case there is no guarantee that the event will be raised (e.g. if the property is updated from outside the class) – Thomas Levesque Oct 28 '11 at 20:25
  • @ThomasLevesque, CodeNaked: That's my point... you _COULD_ call OnPropertyChanged anywhere else in the class, but that's only somewhat useful for OneWay properties (where only the getter matters and the setter is private/protected). I've never used this method, but it is possible was the point. – myermian Oct 28 '11 at 20:35
  • 2
    The only case where I don't call OnPropertyChanged in the setter is for properties that are calculated and have no getter. In that case I call OnPropertyChanged for this property when a property on which it depends is updated – Thomas Levesque Oct 28 '11 at 20:51
  • So how would connect the combobox that's holding the month that I want send to the OnPropertyChanged? – TMan Oct 28 '11 at 21:42
  • I'm confused on actually how to implement all the above info. I want to switch from month to month and I every time I would choose a new month and year it would display the calender for that date. – TMan Oct 28 '11 at 23:52
5

When you bind to a property (even if that property is an ObservableCollection), any changes to the PROPERTY (not the contents of the property) should raise the PropertyChanged event.

An ObservableCollection is self-contained when it comes to raising the CollectionChanged event, so don't worry about firing off an event for the ItemsSource items themselves.

XAML:

<!-- This says that ItemsSource is bound to the Campers property... -->
<ItemsControl ItemsSource="{Binding Path=Campers, Mode=OneWay}" />

CLASS:

public class TheViewModel()
{
   private ObservableCollection<Camper> _campers;
   public ObservableCollection<Camper> Campers
   {
       get { return _campers; }
       set
       {
           if (Equals(_campers, value)) return;

           _campers = value;
           RaisePropertyChanged("Campers"); //Or however you implement it
       }
   }

   private void SomeFunc()
   {
       var bindingCamper = new BindingCamper();

       Campers = bindingCamper.Campers; //This will fire the event
       //etc.
   }

}


Alternatively, if your BindingCamper is your ViewModel then you do the same thing in there instead.

mafu
  • 31,798
  • 42
  • 154
  • 247
myermian
  • 31,823
  • 24
  • 123
  • 215
2

When you change a property from code behind and you wanna update your UI then you use INotifyPropertyChanged inteface. As i see you implemented the interface and even set up a helper to use it just you used an int as parameter you should use a string instead. If you set the property then just call your helper with the right PropertyName and you are good to go.

Like this:

 public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

And to trigger the event to notify the UI:

NotifyPropertyChanged("YourPropertyName");

Maybe you will need to set the TwoWay binding too but that's only true if you wanna change the property from the UI too.

BigL
  • 1,631
  • 1
  • 11
  • 10