【问题标题】:INotifyPropertyChanged and ObservableCollection WPFINotifyPropertyChanged 和 ObservableCollection WPF
【发布时间】:2011-12-17 13:36:51
【问题描述】:

现在我有一个只显示一个月的日历(我过去的月份)。我试图让用户从组合框中选择月份和年份并更新日历。我正在使用我熟悉的 observablecollection 进行绑定。我不知道 INotifyPropertyChanged 是如何工作的。我以前从未使用过它。非常感谢任何帮助或建议。这是我目前所拥有的:

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

---这是另一个计算每个日期在网格上的位置的类----

           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;

---这个类使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>();
    }

【问题讨论】:

    标签: c# wpf visual-studio inotifypropertychanged


    【解决方案1】:

    这就是您通常实现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...
    
    }
    

    基本上,您只需要在每次更新属性时触发PropertyChanged 事件,因此每个setter 都必须调用OnPropertyChanged。请注意,您不能使用自动实现的属性来执行此操作,因为您需要在 setter 中添加自定义逻辑。

    【讨论】:

    • 您可以使用自动实现的属性来执行此操作,但建议不要这样做。最好是自包含 OnPropertyChanged,而不是依靠代码更改它们来触发它。不过,这实际上只适用于 OneWay 属性,因为 UI 不应该能够触发 OnPropertyChanged。
    • @m-y - 如何使用自动实现的属性实现 INotifyPropertyChanged?
    • @my,当然,您可以从类中的任何位置调用 OnPropertyChanged,但在这种情况下,不能保证会引发事件(例如,如果从类外部更新属性)
    • @ThomasLevesque, CodeNaked:这就是我的意思...你可以在类中的任何其他位置调用 OnPropertyChanged,但这仅对 OneWay 属性有点用处(只有 getter 很重要)并且 setter 是私有的/受保护的)。我从来没有使用过这种方法,但这可能是重点。
    • 我不在 setter 中调用 OnPropertyChanged 的​​唯一情况是用于计算且没有 getter 的属性。在这种情况下,当更新它所依赖的属性时,我为此属性调用 OnPropertyChanged
    【解决方案2】:

    当您绑定到某个属性(即使该属性是 ObservableCollection)时,对 PROPERTY(不是属性的内容)的任何更改都应该引发 PropertyChanged 事件。

    在引发 CollectionChanged 事件时,ObservableCollection 是自包含的,因此不必担心会为 ItemsSource 项本身触发事件。

    XAML:

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

    类:

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

    }


    或者,如果您的 BindingCamper 您的 ViewModel,那么您可以在其中执行相同的操作。

    【讨论】:

      【解决方案3】:

      当您从后面的代码更改属性并且想要更新您的 UI 时,您可以使用 INotifyPropertyChanged 接口。正如我所见,您实现了接口,甚至设置了一个助手来使用它,只是您使用 int 作为参数,您应该使用字符串。如果您设置了属性,那么只需使用正确的 PropertyName 调用您的助手,您就可以开始了。

      像这样:

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

      并触发事件通知UI:

      NotifyPropertyChanged("YourPropertyName");
      

      也许您也需要设置 TwoWay 绑定,但仅当您也想从 UI 更改属性时才适用。

      【讨论】:

        猜你喜欢
        • 2021-04-29
        • 1970-01-01
        • 2011-06-03
        • 1970-01-01
        • 1970-01-01
        • 2011-06-25
        • 2012-04-05
        • 2021-09-07
        相关资源
        最近更新 更多