INotifyPropertyChanged 和 ObservableCollection WPF
Posted
技术标签:
【中文标题】INotifyPropertyChanged 和 ObservableCollection WPF【英文标题】:INotifyPropertyChanged and 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>();
【问题讨论】:
【参考方案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 更改属性时才适用。
【讨论】:
以上是关于INotifyPropertyChanged 和 ObservableCollection WPF的主要内容,如果未能解决你的问题,请参考以下文章
使用属性... INotifyPropertyChanged
NHibernate 和 INotifyPropertyChanged
IObservable<T> 和 INotifyPropertyChanged - 是不是存在连接
[译]WPF MVVM 架构 Step By Step(添加actions和INotifyPropertyChanged接口)